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:
- Ensure the
QWR XR Originprefab is in your scene - The prefab already includes the
QWRNetworkManagercomponent - 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:
- Create a prefab for your custom avatar
- 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:
- Add the
QWRNetworkObjectcomponent - 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
QWRNetworkObjectcomponent 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:
- Sample Projects: See examples of multiplayer applications
- Tutorials: Follow step-by-step tutorials for setting up multiplayer
- API Reference: Explore the detailed API documentation