Skip to main content

Multiplayer Networking

QWR SDK provides built-in networking support for creating multiplayer XR experiences. This page explains how to set up and customize multiplayer functionality in your application.

Multiplayer Overview

The multiplayer system in QWR SDK includes:

  • Avatar representation with hand and controller synchronization
  • Object ownership and synchronization
  • Voice communication integration
  • Room-based matchmaking
  • Network physics and interactions

Core Components

QWRNetworkManager

The QWRNetworkManager is the central component that manages all networking functionality.

// Access the network manager
QWRNetworkManager networkManager = QWRNetworkManager.Instance;

// Start hosting a session
networkManager.StartHost(roomName: "MyRoom", maxPlayers: 8);

// Join an existing session
networkManager.JoinRoom(roomCode: "ABC123");

// Disconnect from the current session
networkManager.Disconnect();

// Check connection status
bool isConnected = networkManager.IsConnected;
bool isHost = networkManager.IsHost;

QWRNetworkPlayer

The QWRNetworkPlayer component represents a player in the network.

// Get the local player
QWRNetworkPlayer localPlayer = QWRNetworkManager.Instance.LocalPlayer;

// Get all connected players
QWRNetworkPlayer[] allPlayers = QWRNetworkManager.Instance.GetAllPlayers();

// Check player properties
string playerName = localPlayer.PlayerName;
string playerId = localPlayer.PlayerId;
bool isLocal = localPlayer.IsLocal;

QWRNetworkObject

The QWRNetworkObject component makes an object synchronize over the network.

// Get the network object component
QWRNetworkObject networkObject = GetComponent<QWRNetworkObject>();

// Check ownership
bool isOwner = networkObject.IsOwner;
QWRNetworkPlayer owner = networkObject.Owner;

// Transfer ownership
networkObject.TransferOwnership(targetPlayer);

// Destroy networked object
networkObject.NetworkDestroy();

Setting Up Multiplayer

Basic Setup

To set up multiplayer in your scene:

  1. Ensure the QWR XR Origin prefab is in your scene
  2. The prefab already includes the QWRNetworkManager component
  3. Configure the network settings in the Inspector
// Example: Basic multiplayer setup
public void SetupMultiplayer()
{
// Configure network settings
QWRNetworkManager.Instance.maxPlayers = 8;
QWRNetworkManager.Instance.roomTimeout = 300; // 5 minutes
QWRNetworkManager.Instance.autoReconnect = true;

// Set player information
QWRNetworkManager.Instance.SetPlayerName("Player" + Random.Range(1000, 9999));

// Connect to a room
QWRNetworkManager.Instance.JoinOrCreateRoom("DefaultRoom");
}

Network Authentication

QWR SDK uses Unity's Authentication service for secure connections:

// Authenticate player
async void AuthenticatePlayer()
{
bool success = await QWRNetworkManager.Instance.AuthenticateAsync();

if (success)
{
Debug.Log("Authentication successful");
// Now you can join or create rooms
}
else
{
Debug.LogError("Authentication failed");
}
}

Player Representation

Avatar Synchronization

The SDK automatically synchronizes player avatars, including:

  • Head position and rotation
  • Hand positions and animations
  • Controller positions and inputs
// Configure avatar settings
QWRNetworkAvatar avatar = QWRNetworkManager.Instance.LocalPlayerAvatar;
avatar.syncHandAnimations = true;
avatar.syncControllerInputs = true;
avatar.updateRate = 30; // Updates per second

Custom Avatar Models

You can use custom avatar models:

  1. Create a prefab for your custom avatar
  2. Assign it to the QWRNetworkManager
// Set custom avatar prefab
QWRNetworkManager.Instance.playerAvatarPrefab = myCustomAvatarPrefab;

Object Synchronization

Making Objects Network-Aware

To make an object synchronize over the network:

  1. Add the QWRNetworkObject component
  2. Configure synchronization settings
// Example: Creating a networked object
public GameObject CreateNetworkedObject(Vector3 position)
{
// Create a cube
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = position;

// Add rigidbody
Rigidbody rb = cube.AddComponent<Rigidbody>();

// Add network object component
QWRNetworkObject networkObject = cube.AddComponent<QWRNetworkObject>();
networkObject.syncPosition = true;
networkObject.syncRotation = true;
networkObject.syncScale = true;
networkObject.syncPhysics = true;

// Register with network manager
QWRNetworkManager.Instance.RegisterNetworkObject(networkObject);

return cube;
}

Ownership and Authority

Each networked object has an owner who has authority over it:

// Check ownership
bool isOwner = networkObject.IsOwner;

// Transfer ownership
networkObject.TransferOwnership(targetPlayer);

// Request ownership
networkObject.RequestOwnership();

// Subscribe to ownership events
networkObject.OnOwnershipChanged += HandleOwnershipChanged;

// Example event handler
private void HandleOwnershipChanged(QWRNetworkObject obj, QWRNetworkPlayer newOwner)
{
Debug.Log($"Object {obj.name} ownership transferred to {newOwner.PlayerName}");
}

Synchronization Options

You can configure what properties are synchronized:

// Configure synchronization options
QWRNetworkObject networkObject = GetComponent<QWRNetworkObject>();
networkObject.syncPosition = true;
networkObject.syncRotation = true;
networkObject.syncScale = false;
networkObject.syncPhysics = true;
networkObject.syncActiveState = true;
networkObject.updateRate = 20; // Updates per second

Network Interactions

Networked Interactables

The SDK includes a QWRNetworkInteractable component for synchronizing interactions:

// Add networked interactable component
QWRNetworkInteractable networkInteractable = cube.AddComponent<QWRNetworkInteractable>();

// Configure networked interaction settings
networkInteractable.autoTransferOwnershipOnGrab = true;
networkInteractable.releaseOwnershipOnRelease = false;

Ownership Transfer on Interaction

By default, ownership is transferred when an object is grabbed:

// Configure ownership transfer settings
networkInteractable.autoTransferOwnershipOnGrab = true;
networkInteractable.ownershipTransferDelay = 0.1f;

Voice Communication

QWR SDK integrates with Unity's Vivox service for voice chat:

// Access the voice chat system
QWRVoiceChat voiceChat = QWRNetworkManager.Instance.VoiceChat;

// Configure voice chat settings
voiceChat.enabled = true;
voiceChat.microphoneVolume = 0.8f;
voiceChat.speakerVolume = 1.0f;
voiceChat.spatialAudio = true;
voiceChat.voiceActivation = true;
voiceChat.activationThreshold = 0.02f;

// Mute/unmute microphone
voiceChat.MuteMicrophone(mute: true);

// Mute/unmute specific player
voiceChat.MutePlayer(playerId, mute: true);

Room Management

Creating and Joining Rooms

// Create a new room
async void CreateRoom()
{
bool success = await QWRNetworkManager.Instance.CreateRoomAsync(
roomName: "My Room",
maxPlayers: 8,
isPrivate: false
);

if (success)
{
string roomCode = QWRNetworkManager.Instance.CurrentRoomCode;
Debug.Log($"Room created with code: {roomCode}");
}
}

// Join an existing room
async void JoinRoom(string roomCode)
{
bool success = await QWRNetworkManager.Instance.JoinRoomAsync(roomCode);

if (success)
{
Debug.Log("Joined room successfully");
}
else
{
Debug.LogError("Failed to join room");
}
}

Room Events

// Subscribe to room events
QWRNetworkManager.Instance.OnRoomJoined += HandleRoomJoined;
QWRNetworkManager.Instance.OnRoomLeft += HandleRoomLeft;
QWRNetworkManager.Instance.OnPlayerJoined += HandlePlayerJoined;
QWRNetworkManager.Instance.OnPlayerLeft += HandlePlayerLeft;

// Example event handlers
private void HandleRoomJoined(string roomCode)
{
Debug.Log($"Joined room: {roomCode}");
}

private void HandlePlayerJoined(QWRNetworkPlayer player)
{
Debug.Log($"Player joined: {player.PlayerName}");
}

Custom Network Messages

You can send custom network messages between players:

// Define message types
public enum MessageType
{
GameStart,
GameEnd,
ScoreUpdate
}

// Send a custom message
public void SendCustomMessage(MessageType type, string data)
{
QWRNetworkManager.Instance.SendCustomMessage((int)type, data);
}

// Subscribe to custom messages
void Start()
{
QWRNetworkManager.Instance.OnCustomMessageReceived += HandleCustomMessage;
}

// Handle custom messages
private void HandleCustomMessage(QWRNetworkPlayer sender, int messageType, string data)
{
MessageType type = (MessageType)messageType;

switch (type)
{
case MessageType.GameStart:
StartGame();
break;
case MessageType.GameEnd:
EndGame();
break;
case MessageType.ScoreUpdate:
UpdateScore(int.Parse(data));
break;
}
}

Network Physics

QWR SDK includes a network physics system for synchronizing physical interactions:

// Configure network physics
QWRNetworkPhysics networkPhysics = GetComponent<QWRNetworkPhysics>();
networkPhysics.interpolationMode = NetworkInterpolationMode.Linear;
networkPhysics.extrapolationMode = NetworkExtrapolationMode.Limited;
networkPhysics.syncVelocity = true;
networkPhysics.syncAngularVelocity = true;

Performance Considerations

Networking can be resource-intensive. Here are some optimization tips:

  • Adjust update rates based on object importance
  • Use ownership to limit who can modify objects
  • Consider using area of interest management
  • Optimize avatar synchronization settings
  • Use compression for network transforms
// Configure network optimization settings
QWRNetworkManager.Instance.compressionLevel = NetworkCompressionLevel.Medium;
QWRNetworkManager.Instance.areaOfInterestEnabled = true;
QWRNetworkManager.Instance.areaOfInterestRadius = 10f;

Platform-Specific Considerations

Different platforms have varying networking capabilities:

  • Quest/Meta Devices: Full support for all networking features
  • PC VR: Full support with potentially higher bandwidth
  • Mobile VR: Limited bandwidth, consider optimizing network traffic
  • Cross-Platform: Test thoroughly across all target platforms

Troubleshooting

Connection Issues

If you experience connection problems:

  • Check internet connectivity
  • Verify authentication settings
  • Ensure the room code is correct
  • Check for firewall or NAT issues

Synchronization Problems

If objects aren't synchronizing correctly:

  • Verify that the QWRNetworkObject component is properly configured
  • Check ownership settings
  • Adjust synchronization update rates
  • Verify that the object is registered with the network manager

Voice Chat Issues

If voice chat isn't working:

  • Check microphone permissions
  • Verify that Vivox services are properly initialized
  • Adjust microphone sensitivity settings
  • Check if the player is muted

Next Steps

Now that you understand multiplayer networking, you can explore: