LoadSceneFromSharedRooms with alignmentData.groupUuid), and others act as Guests (discover and load it).



// Shares multiple MRUK rooms with a group
public OVRTask<OVRResult<OVRAnchor.ShareResult>> ShareRoomsAsync(
IEnumerable<MRUKRoom> rooms,
Guid groupUuid);
// Loads scene data shared by Host, optionally aligned to their floor anchor
public async Task<LoadDeviceResult> LoadSceneFromSharedRooms(
IEnumerable<Guid> roomUuids, Guid groupUuid,
(Guid alignmentRoomUuid, Pose floorWorldPoseOnHost)? alignmentData,
bool removeMissingRooms = true);
public async void StartColocation()
{
var advertisement = await OVRColocationSession.StartAdvertisementAsync(null);
Guid groupUuid = advertisement.Value;
// TODO: Store groupUuid in a networked variable to later share with guests
}
public async void ShareMrukRoom(Guid groupUuid)
{
var room = MRUK.Instance.GetCurrentRoom();
await room.ShareRoomAsync(groupUuid);
// TODO: Store the room's floor pose as a string in a networked variable to later share with guests
}
public async void LoadSharedRoom(Guid groupUuid, Guid roomUuid, string poseString)
{
// TODO: Parse poseString into a Pose (see step 5)
Pose pose = ParsePose(poseString);
MRUK.Instance.LoadSceneFromSharedRooms(null, groupUuid, (roomUuid, pose));
}
LoadSceneFromSharedRooms with the alignmentData parameter. Ensure EnableWorldLock = true so MRUK adjusts the camera’s tracking space, aligning both devices.// Host: Serialize and send floor-anchor pose
public void SendAlignmentData(Guid roomUuid)
{
var room = MRUK.Instance.GetCurrentRoom();
var floor = room.FloorAnchor.transform;
string poseString = $"{floor.position.x},{floor.position.y},{floor.position.z},"
+ $"{floor.rotation.x},{floor.rotation.y},"
+ $"{floor.rotation.z},{floor.rotation.w}";
// TODO: Send both 'roomUuid' and 'poseString' to Guests
}
// Guest: Parse received pose string back into a Pose
public Pose ParsePose(string poseString)
{
var p = poseString.Split(',');
return new Pose(
new Vector3(
float.Parse(p[0]),
float.Parse(p[1]),
float.Parse(p[2])
),
new Quaternion(
float.Parse(p[3]),
float.Parse(p[4]),
float.Parse(p[5]),
float.Parse(p[6])
)
);
}
☕ Complete Space Sharing Implementation using Photon Fusion
using System;
using System.Linq;
using Fusion;
using UnityEngine;
using Meta.XR.MRUtilityKit;
public class SpaceSharingManager : NetworkBehaviour
{
[Networked] private NetworkString<_512> NetworkedRoomUuid { get; set; }
[Networked] private NetworkString<_256> NetworkedRemoteFloorPose { get; set; }
private Guid _sharedAnchorGroupId;
public override void Spawned()
{
base.Spawned();
PrepareColocation();
}
private void PrepareColocation()
{
if (Object.HasStateAuthority)
{
AdvertiseColocationSession();
}
else
{
DiscoverNearbySession();
}
}
private async void AdvertiseColocationSession()
{
var result = await OVRColocationSession.StartAdvertisementAsync(null);
if (!result.Success)
{
Debug.LogError($"[Host] Advertisement failed: {result.Status}");
return;
}
_sharedAnchorGroupId = result.Value;
Debug.Log($"[Host] Advertisement started. Group UUID: {_sharedAnchorGroupId}");
ShareMrukRooms();
}
// Shares the current room of the host's MRUK instance.
// If you would like to share all rooms follow these steps:
// var rooms = MRUK.Instance.Rooms;
// var result = await MRUK.Instance.ShareRoomsAsync(rooms, _sharedAnchorGroupId);
// NetworkedRoomUuid = string.Join(",", rooms.Select(r => r.Anchor.Uuid));
// var pose = room.FloorAnchor.transform;
private async void ShareMrukRooms()
{
var room = MRUK.Instance.GetCurrentRoom();
NetworkedRoomUuid = room.Anchor.Uuid.ToString();
Debug.Log($"[Host] Sharing MRUK room: {room.Anchor.Uuid}");
var result = await room.ShareRoomAsync(_sharedAnchorGroupId);
if (!result.Success)
{
Debug.LogError($"[Host] Failed to share MRUK room: {result.Status}");
return;
}
Debug.Log("[Host] MRUK room shared successfully.");
var pose = room.FloorAnchor.transform;
NetworkedRemoteFloorPose = $"{pose.position.x}, {pose.position.y},
{pose.position.z}," +
$"{pose.rotation.x}, {pose.rotation.y},
{pose.rotation.z},{pose.rotation.w}";
Debug.Log($"[Host] Set NetworkedRemoteFloorPose = {NetworkedRemoteFloorPose}");
}
private async void DiscoverNearbySession()
{
OVRColocationSession.ColocationSessionDiscovered += OnSessionDiscovered;
var result = await OVRColocationSession.StartDiscoveryAsync();
if (!result.Success)
{
Debug.LogError($"[Client] Discovery failed: {result.Status}");
}
else
{
Debug.Log("[Client] Discovery started successfully.");
}
}
private void OnSessionDiscovered(OVRColocationSession.Data session)
{
OVRColocationSession.ColocationSessionDiscovered -= OnSessionDiscovered;
_sharedAnchorGroupId = session.AdvertisementUuid;
Debug.Log($"[Client] Discovered session: {_sharedAnchorGroupId}");
LoadSharedRoom(_sharedAnchorGroupId);
}
private static Pose ParsePose(string poseString)
{
var parts = poseString.Split(',');
if (parts.Length == 7)
{
return new Pose(
new Vector3(float.Parse(parts[0]), float.Parse(parts[1]),
float.Parse(parts[2])),
new Quaternion(
float.Parse(parts[3]), float.Parse(parts[4]),
float.Parse(parts[5]), float.Parse(parts[6]))
);
}
Debug.LogError("Invalid pose string: " + poseString);
return default;
}
// Loads the rooms previously shared with the user.
// If you want to load multiple rooms, parse all room guids and
// include them in the LoadSceneFromSharedRooms method instead of "null".
private async void LoadSharedRoom(Guid groupUuid)
{
Debug.Log($"[Client] Loading shared MRUK room: {groupUuid}");
var roomUuid = Guid.Parse(NetworkedRoomUuid.ToString());
var remotePoseStr = NetworkedRemoteFloorPose.ToString();
var remoteFloorWorldPose = ParsePose(remotePoseStr);
var result = await MRUK.Instance.LoadSceneFromSharedRooms(
null,
groupUuid,
(roomUuid, remoteFloorWorldPose));
if (result == MRUK.LoadDeviceResult.Success)
{
Debug.Log("[Client] Successfully loaded and aligned to shared room.");
}
else
{
Debug.LogError($"[Client] Failed to load shared MRUK room: {result}");
}
}
}


🛠️ OpenXR Plugin Support
🛠️ Scene Anchor Misalignment
🛠️ Local Anchor Storage Limit