# Shared AR Host & Peers Communication: A Peer-to-Peer Solution

**URL:** <https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446>\
**Category:** I'm Stuck\
**Created:** [August 1, 2022, 11:56pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446 "2022-08-01T23:56:07Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![rob\_link](https://sea2.discourse-cdn.com/niantic/user_avatar/community.nianticspatial.com/rob_link/32/1176_2.png) [@rob\_link](https://community.nianticspatial.com/u/rob_link)\
**Post date:** [August 1, 2022, 11:56pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/1 "2022-08-01T23:56:07Z")

</div>

> _These steps are intended to be a temporary alternative solution while we update the existing guide._

Hello Lightship development community!

There are a few known issues you may encounter if you follow the [Shared AR Host & Peers Communication](https://lightship.dev/guides/shared-ar-host-peer-communication/) guide that can result in…

![01_host_events](https://us1.discourse-cdn.com/niantic/original/2X/7/73bc1f65dfd7e244a23d80d0ccb482799a86f6ad.gif)  
…the host device not sharing tap events with peers…

![02_closiong_app](https://us1.discourse-cdn.com/niantic/original/2X/c/cd976c342b230ea19020e11b6f5d0f225adac752.gif)  
…the peer car persisting on the host device after closing the app…

![03_loading_scene](https://us1.discourse-cdn.com/niantic/original/2X/6/69e2c82e0192e38803dc3083e9e9f1677198af6b.gif)  
…the peer car persisting on the host device when the peer loads into another scene, such as the SceneSelector published with ARDK Examples…

![04_peer_not_loading_host](https://us1.discourse-cdn.com/niantic/original/2X/c/c65a525a7bc91509673a2eca1e8c512170818b4d.gif)  
…or the peer car not loading in a pre-existing host car after connecting.

If you’re trying to create a network multiplayer sample scene but have run into the issues with the published guide, you can follow these steps as an alternative peer-to-peer solution that addresses the issues listed above. Let’s build!

**NOTE:** These steps demonstrate creating the ARDK components manually rather than using the manager components.

* * *

1. First, begin with a fresh scene.  
 ![05_new_scene](https://us1.discourse-cdn.com/niantic/original/2X/8/8c76addce787e80ad93554545d346bc0ef44eb08.jpeg)

* * *

1. Then, alter the `Main Camera` GameObject’s Camera component so that the `Clear Flags` field is set to `Solid Color`, and the `Background` field is set to black.  
 ![06_camera_component](https://us1.discourse-cdn.com/niantic/original/2X/1/153e0002d727d0c9e5119465d1ec87912c64996d.jpeg)

* * *

1. Also, add the `AR Camera Position Helper`, `AR Rendering Manager`, and `Android Permission Requester` components to the `Main Camera`, and ensure their camera references and Android permissions are set.  
 ![07_camera_ardk](https://us1.discourse-cdn.com/niantic/original/2X/0/00ee7183c97643374fdc31facfd80c3c9aa1a900.jpeg)

* * *

1. Next, add a new C# script to the `Main Camera` named `P2PGameLogic`.

**Note:** The following steps go through the script creation process in detail. The resulting script – with in-line comments – is available for download, attached below this post.

 ![08_add_script](https://us1.discourse-cdn.com/niantic/original/2X/f/ffe5966f0fca4764126d7e7e1defd9ed47b6ae98.jpeg)

* * *

1. Open the script and start by adding the following using statements to the top of the file:

```auto
using Niantic.ARDK.AR;
using Niantic.ARDK.AR.Configuration;
using Niantic.ARDK.AR.Networking;
using Niantic.ARDK.AR.HitTest;
using Niantic.ARDK.Networking;
using Niantic.ARDK.Networking.MultipeerNetworkingEventArgs;
using Niantic.ARDK.Utilities;
using Niantic.ARDK.Utilities.BinarySerialization;
using Niantic.ARDK.Utilities.Input.Legacy;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;

```

![09_using_statements](https://us1.discourse-cdn.com/niantic/original/2X/2/26a0a1249061543481fa9a1834f0022da73fa8f6.png)

* * *

1. Within the scope of the `P2PGameLogic` class – but outside the scope of a method – declare private fields of the following types:

- `IARWorldTrackingConfiguration`
- `IMultipeerNetworking`
- `IARSession`
- `IARNetworking`  
 ![10_add_fields](https://us1.discourse-cdn.com/niantic/original/2X/3/3c943c498ae596d272f3f776162a149079667a96.png)

* * *

1. Within the `P2PGameLogic` class, create a `private void OnEnable()` method and initialize the four ARDK objects that were declared in the previous step during this callback.  
 ![11_initialize](https://us1.discourse-cdn.com/niantic/original/2X/1/154e3443ca552b8e1becb16890365c58222cdd3e.png)

* * *

1. Alongside the `OnEnable()` method, create a `private void OnDisable()` method, and dispose of the four aforementioned objects during this callback.  
 ![12_dispose](https://us1.discourse-cdn.com/niantic/original/2X/3/369b482710ac7d5b2c64708c4c49bdb0c1cc083d.png)

* * *

1. Within the scope of the `P2PGameLogic` class – but outside the scope of a method – declare and initialize a byte array to represent the session identifier.

**Note:** In this example, we’ve hardcoded a string “SampleSessionID” to represent the session identifier.  
 ![13_samplesessionid](https://us1.discourse-cdn.com/niantic/original/2X/b/bdfba22de56dd1b6654783d1b8fe3df1acdc790e.png)

* * *

1. During the `Start()` method of the `P2PGameLogic` class, call the `Run()` method of the `ARSession` field belonging to the `IARNetworking` object, passing in the `IARWorldTrackingConfiguration` object. Afterwards, join the networking session by passing the byte array that represents the session identifier into the `Join()` method of the `Networking` field that belongs to the `IARNetworking` object.  
 ![14_start](https://us1.discourse-cdn.com/niantic/original/2X/f/f83a8ad77bbdd20bc44bac29052e56d6f15d0523.png)

* * *

1. Within the scope of the `P2PGameLogic` class, create a series of callback methods that will listen for networking-related events raised by the `IMultipeerNetworking` object. We’ll write the methods first – including some logging statements to assist with potential troubleshooting later – and then we’ll subscribe the callbacks to the relevant event handlers in the next step.  
 ![15_callbackmethods](https://us1.discourse-cdn.com/niantic/original/2X/9/998e26ccf9bdc14b2061ea2276cb246c928e5510.png)

* * *

1. With the callback methods written, subscribe them to the relevant `IMultipeerNetworking` events during the `OnEnable()` method…  
 ![16_subscribeevents](https://us1.discourse-cdn.com/niantic/original/2X/5/5878485ca384c107916a2de191fd3fed1d2a137a.png)

* * *

1. …and be sure to unsubscribe the callback methods during the `OnDisable()` method, prior to disposing of the objects.  
 ![17_unsubscribeevents](https://us1.discourse-cdn.com/niantic/original/2X/0/0c658f5cc4a6a9032bb2657bab5e9c4dc5b5033f.png)

* * *

1. Within the scope of the `P2PGameLogic` class, declare a pair of public fields – one to store the scene’s `Camera` component, and another to store the `GameObject` that represents the car prefab. Also, declare a `private GameObject` field that will contain a reference to the car that belongs to the local device, as well as a constant unsigned integer to represent the car positioning event that gets broadcast to other devices in the network session.  
 ![18_additionalfields](https://us1.discourse-cdn.com/niantic/original/2X/2/2189d8a9f2d4571a4cfcf1c657406a7506f2ff57.png)

* * *

1. After saving the `P2PGameLogic` script, return to the scene and set the references to the `Camera` component of the `Main Camera` GameObject and the `CAR` prefab that comes with the Lightship Hub samples.  
 ![19_setfields](https://us1.discourse-cdn.com/niantic/original/2X/d/dfa382615c278ce56b87841b5eea1ee50eea0512.jpeg)

* * *

1. Ensure you’re setting the `Car Prefab` field to the .prefab object, and not the .fbx object of the same name.  
 ![20_car](https://us1.discourse-cdn.com/niantic/original/2X/c/c940fc4e6d56287a6b238888355d6f229b716d04.png)

* * *

1. Within the `Update()` method belonging to the `P2PGameLogic` class, include the following logic that first checks for a tap on the screen, then performs a hit test. If the hit-test is successful, create a car for the local player at the tapped location if the car doesn’t already exist, or set its destination if it already does exist. Finally, broadcast the car’s position to other players on the network.

**Note:** The `CreateCar()` and `BroadcastCarPosition()` methods will be written in the following steps, so disregard any error indicators suggesting that the methods do not yet exist.

 ![21_update](https://us1.discourse-cdn.com/niantic/original/2X/7/7e57a1fda94f698c3b3e7b94cdded952a12165af.png)

* * *

1. Within the scope of the `P2PGameLogic` class, write a `CreateCar()` method that takes in a `Vector3 position`, and returns the GameObject of the car that was created at that position.  
 ![22_createcar](https://us1.discourse-cdn.com/niantic/original/2X/9/981b08ff4163afc720ea5581d21fb680878c7321.png)

* * *

1. Within the scope of the `P2PGameLogic` class, write a `BroadcastCarPosition()` method that takes in a `Vector3 position`, serializes it into a `MemoryStream` object, and sends it to other peers in the networking session.  
 ![23_broadcastcarposition](https://us1.discourse-cdn.com/niantic/original/2X/f/f54e598c3d60c24ef41e215a4c33cd29450eb39c.png)

* * *

1. Within the scope of the `P2PGameLogic` class, declare and initialize a dictionary where they key-value pair is a `GUID` and `GameObject`. This will be populated on each device with the players (the `GUID`) and the car associated with that player (the `GameObject`).  
 ![24_playersdictionary](https://us1.discourse-cdn.com/niantic/original/2X/5/5711821cc3568e8ea0eef86663045d2d9079c707.png)

* * *

1. Within the `OnPeerDataReceived()` callback method, respond to the signal by first copying the arguments into a new `MemoryStream` object and storing the sender’s identifier. Then, in the case of receiving a position event, deserialize the position from the `MemoryStream` as a `Vector3`, and either set the remote player’s car’s position if that player is already in the local dictionary or create a car for that remote player and add them to the dictionary if they’re not yet added.  
 ![25_peerdatareceived](https://us1.discourse-cdn.com/niantic/original/2X/0/06fe0271c3088d7788f18f2cba691d2ec64388b4.png)

* * *

1. Within the `OnPeerAdded()` callback method, call the `BroadcastCarPosition()` method to ensure that peers that connect to the network are made aware of any pre-existing cars.  
 ![26_onpeeradded](https://us1.discourse-cdn.com/niantic/original/2X/9/9d99eb02d83cd253942da2aff691f0e191c8f987.png)

* * *

1. Within the `OnPeerRemoved()` callback method, be sure to remove the player that left from the local dictionary, and destroy their car in the process.  
 ![27_onpeerremoved](https://us1.discourse-cdn.com/niantic/original/2X/0/0ed50e3d0f03c7f3eb218e479ebfb2aca38b0df1.png)

* * *

1. Within the scope of the `P2PGameLogic` class, write a `LeaveNetworkingSession()` method that calls the `Leave()` method of the `IMultipeerNetworking` object.  
 ![28_leavenetworkingsession](https://us1.discourse-cdn.com/niantic/original/2X/9/9525ef5b3146c196931f1da6657a9c66b6c56622.png)

* * *

1. Call the `LeaveNetworkingSession()` method at the beginning of `OnDisable()` to ensure the player leaves the session when loading into a different scene.  
 ![29_leaveondisable](https://us1.discourse-cdn.com/niantic/original/2X/b/b9905d121a486bb130ec7b9225af48708d87ee4e.png)

* * *

1. Within the `P2PGameLogic` class, create a `private void OnApplicationQuit()` method and call the `LeaveNetworkingSession()` method within it to ensure the player leaves the session when they force-quit the app.  
 ![30_leaveonapplicationquit](https://us1.discourse-cdn.com/niantic/original/2X/2/2d82724b18da6c4d3bb8487ccaef0d2d276a4e8c.png)

* * *

1. Ensure your scene is added to your Build Settings, and try testing on a pair of test devices.

**Note:** Before building, don’t forget to set up any project-wide settings for ARDK, such as the ARDKAuthConfig object that requires a valid API key generated by your Lightship account.

* * *

Now, you should be able to observe…

![31_host_events_fixed](https://us1.discourse-cdn.com/niantic/original/2X/b/b936e2bc534b6ff59193b0dadb536acb2aa6141b.gif)  
…the host device shares its tap events with peers…

![32_closing_app_fixed](https://us1.discourse-cdn.com/niantic/original/2X/4/4c528445b504b588c61a3bba821119a076ae6fe2.gif)  
…the peer car is cleaned up when closing the app…

![33_loading_scene_fixed](https://us1.discourse-cdn.com/niantic/original/2X/b/b74f3d4ec688428de419db045ee9e2cd18760ee1.gif)  
…the peer car is also cleaned up when loading into another scene…

![34_peer_loading_host](https://us1.discourse-cdn.com/niantic/original/2X/7/7d787f851a92b888b4285074d5939cad4b27f21d.gif)  
…and the peer device loads a pre-existing host car after connecting.

**Note:** By default, the networking classes will emit a variety of debug output to the console window. However, the debug statements generated by the code written above are prefixed by `“Lightship: “`. If you’d like to see the debug statements specific to this code, you can filter your debug output with the `“Lightship: “` prefix to only see the debug statements that we wrote as part of `P2PGameLogic.cs`.

 ![35_logs](https://us1.discourse-cdn.com/niantic/original/2X/a/a5c53ba199b50d1d824af22024939cf28b2ddc2b.png)

* * *

Thanks for following along with this alternative solution, and we look forward to seeing any networking projects you build with ARDK! 🚀

📄 [P2PGameLogic.cs](https://community.nianticspatial.com/uploads/short-url/h4PyV9cTETL7le6mR8kGOgBFmxv.cs) (11.3 KB)

---

<div class="post-metadata">

**Author:** ![rob\_link](https://sea2.discourse-cdn.com/niantic/user_avatar/community.nianticspatial.com/rob_link/32/1176_2.png) [@rob\_link](https://community.nianticspatial.com/u/rob_link)\
**Post date:** [August 2, 2022, 12:00am UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/2 "2022-08-02T00:00:18Z")

</div>



---

<div class="post-metadata">

**Author:** ![yasassri](https://sea2.discourse-cdn.com/niantic/user_avatar/community.nianticspatial.com/yasassri/32/705_2.png) [@yasassri](https://community.nianticspatial.com/u/yasassri)\
**Post date:** [August 3, 2022, 3:47am UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/3 "2022-08-03T03:47:52Z")

</div>

Thank you very much for your clear guide. This helps me a lot.

---

<div class="post-metadata">

**Author:** ![Kang-An](https://avatars.discourse-cdn.com/v4/letter/k/8e8cbc/32.png) [@Kang-An](https://community.nianticspatial.com/u/Kang-An)\
**Post date:** [August 3, 2022, 11:47am UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/4 "2022-08-03T11:47:27Z")

</div>

Thanks for this update. Could you share if all this new “P2P” code is meant as a giant bug fix to the guide, or would there be situations where you’d still want to do things similar to the original guide (i.e. the Host-Peer method)? Because from my understanding it just seems like the original guide is buggy (as you showcased at the top of this post) and there’s never a reason to do things that way. Could somebody at Niantic clarify?

---

<div class="post-metadata">

**Author:** ![rob\_link](https://sea2.discourse-cdn.com/niantic/user_avatar/community.nianticspatial.com/rob_link/32/1176_2.png) [@rob\_link](https://community.nianticspatial.com/u/rob_link)\
**Post date:** [August 3, 2022, 4:32pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/5 "2022-08-03T16:32:18Z")

</div>

Hi @Kang-An!

There are issues with the currently published guide that result in bugs, and the team is working on a resolution at this time. These steps are intended to be a temporary alternative to creating a network multiplayer game while the original guide – which follows the authoritative-host model – is undergoing updates.

---

<div class="post-metadata">

**Author:** ![Kang-An](https://avatars.discourse-cdn.com/v4/letter/k/8e8cbc/32.png) [@Kang-An](https://community.nianticspatial.com/u/Kang-An)\
**Post date:** [August 5, 2022, 7:55am UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/6 "2022-08-05T07:55:37Z")

</div>

Hi @rob_link thanks for the clarification. Can I just confirm that the mistakes are with the guide itself, and not bugs in ARDK? Looking at the guide (without testing the code myself) it does seem to lack some steps that would cause the bugs showcased in this thread. I think I’d be able to fix it and just want to confirm that there aren’t any inherent bugs with ARDK if I wanted to implement a host-client architecture myself.

---

<div class="post-metadata">

**Author:** ![Connor\_McClelland](https://avatars.discourse-cdn.com/v4/letter/c/71c47a/32.png) [@Connor\_McClelland](https://community.nianticspatial.com/u/Connor_McClelland)\
**Post date:** [August 5, 2022, 7:52pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/7 "2022-08-05T19:52:09Z")

</div>

Great post! Does anyone know how this P2P method would compare latency wise to the standard host-client architecture? It seems each individual is somewhat functioning as a host for their own car and a peer for all other players, similar to the normal sense. When I’ve done something similar by having each individual have authority over their own spawned networked objects regardless of being host or not, I would encounter a degrading accuracy with tracking and encounter more latency as the session persists.

---

<div class="post-metadata">

**Author:** ![rob\_link](https://sea2.discourse-cdn.com/niantic/user_avatar/community.nianticspatial.com/rob_link/32/1176_2.png) [@rob\_link](https://community.nianticspatial.com/u/rob_link)\
**Post date:** [August 5, 2022, 8:58pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/8 "2022-08-05T20:58:15Z")

</div>

That’s correct, @Kang-An. The issues are with the steps laid out in the guide and not the ARDK classes. It’s still possible to have the host device be responsible for message distribution if you’d prefer to implement that paradigm.

---

<div class="post-metadata">

**Author:** ![rob\_link](https://sea2.discourse-cdn.com/niantic/user_avatar/community.nianticspatial.com/rob_link/32/1176_2.png) [@rob\_link](https://community.nianticspatial.com/u/rob_link)\
**Post date:** [August 5, 2022, 11:03pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/9 "2022-08-05T23:03:13Z")

</div>

Hi @Connor_McClelland , thank you!

Just to be clear, this alternative guide still uses the host-client setup under the hood. However, the messaging between devices is handled in a peer-to-peer style where all users (regardless if they are the host or a client/peer) are responsible for sending their events to all other users, rather than event messages being passed to the host in order to be re-distributed to the remaining peers.

Latency-wise, the method described in this guide should theoretically result in lower latency overall, as a peer updating its car position is broadcasting a single message to all other users, rather than the message being first sent to the host, then re-broadcast to the remaining peers. However, I wasn’t able to test this in practice so I’d be interested in hearing from anyone experiencing different results.

It is worth noting that – [according to the Lightship docs](https://lightship.dev/docs/ardk/multiplayer/low_level_networking_gotchas.html#:~:text=For%20optimal%20multiplayer%20experiences%2C%20we%20recommend%20no%20more%20than%205%20users%20per%20session%2C%20with%20sessions%20lasting%20up%20to%205%20minutes.) – multiplayer sessions with ARDK should generally consist of five or fewer participating devices with a single session lasting five or fewer minutes.

---

<div class="post-metadata">

**Author:** ![James\_C\_Kane](https://avatars.discourse-cdn.com/v4/letter/j/e9a140/32.png) [@James\_C\_Kane](https://community.nianticspatial.com/u/James_C_Kane)\
**Post date:** [March 15, 2023, 6:49pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/10 "2023-03-15T18:49:01Z")

</div>

This was a great help, thanks for showing this method (I believe the published tutorial still has some of the issues/bugs originally described). Getting consistent networking of position now.

What would be the best way (or is it even possible in the peer-to-peer model) to have a central host controlling some data? For ex, what if both cars are racing to gather some collectible gameObjects strewn around the AR mesh. How would we network collisions w/ the collectables and have a central scorekeeping authority/data source so that score doesn’t de-sync across devices?

---

<div class="post-metadata">

**Author:** ![NianticSpatial](https://avatars.discourse-cdn.com/v4/letter/n/49beb7/32.png) [@NianticSpatial](https://community.nianticspatial.com/u/NianticSpatial)\
**Post date:** [March 5, 2026, 11:14pm UTC](https://community.nianticspatial.com/t/shared-ar-host-peers-communication-a-peer-to-peer-solution/2446/11 "2026-03-05T23:14:46Z")

</div>


