Skip to content

Multiplayer (Pro, Deprecated)

Real-time collaborative industrial automation simulation with support for multiple users and VR/AR integration.

The realvirtual Professional Multiplayer system enables multiple users to simultaneously interact with the same virtual commissioning scenario. Built on Unity Netcode for GameObjects with Unity Relay Service, it provides synchronized automation components, real-time material flow, and collaborative design review capabilities.

  • Multi-user Collaboration: Scalable concurrent users in the same simulation
  • Real-time Synchronization: All automation components (Drives, Sensors, MUs, Sources) synchronized across clients
  • VR/AR Support: Full XR controller tracking and avatar representation
  • Industrial Integration: PLC signal synchronization and automation logic sharing
  • Cloud-based Connection: Unity Relay Service for secure peer-to-peer connections
  • Unity Netcode for GameObjects: Core networking framework
  • Unity Transport (UTP): Network transport layer with DTLS encryption
  • Unity Services Core: Authentication and Unity Services integration
  • XR Interaction Toolkit (optional): For VR/AR functionality
  1. Enable Unity Services in Project Settings → Services
  2. Create Unity Project ID or link to existing project
  3. Enable Relay Service in Unity Dashboard → Multiplayer → Relay
  4. Enable Authentication for anonymous user sessions
  1. Add the Multiplayer Prefab to your scene from the realvirtual Professional package
    • The prefab contains all necessary components: NetworkManager, RelayConnectionManager, NetworkInitializer, and MultiuserWindow
    • All network prefabs are pre-configured and registered automatically
NetworkManager Configuration

NetworkManager configuration showing Unity Transport settings, Relay Connection Manager, and network prefab registration

The system automatically creates networked versions of:

  • Drives: Position and speed synchronization
  • Sensors: Occupancy state synchronization
  • MUs (Moving Units): Transform and identity synchronization
  • Sources: Material generation events
  • Signals: PLC signal values and states
  1. Open Multiuser Window via realvirtual → UI toolbar
  2. Enter Player Name (stored locally)
  3. Click “Host” to create session
  4. Share Join Code with other users
  1. Open Multiuser Window
  2. Enter Player Name
  3. Input Join Code received from host
  4. Click “Client” to join session
Multiuser Window Interface

Multiuser window showing Code input field, Name field, and Host/Client connection buttons with status display

  • Connected: Successfully connected to multiplayer session
  • No Connection: Not connected or connection failed
  • Position Values: Current drive positions
  • Speed Values: Current drive speeds
  • Authority: Host controls drives, clients receive updates
  • Override Mode: Clients use PositionOverwrite and SpeedOverwrite
  • Transform: Position and rotation
  • Identity: LocalID, GlobalID, Name
  • Physics: Host maintains physics authority, clients use kinematic mode
  • Source Tracking: References to creating Source component
  • Occupancy State: Boolean occupied/free status
  • Network Mode: Clients automatically switch to network-controlled mode
  • Real-time Updates: Immediate sensor state propagation
  • Signal Values: All PLC signal types (PLCInputBool, PLCOutputFloat, etc.)
  • Bidirectional: Host-to-client signal synchronization
  • String-based: Universal value representation
  • Player Names: Persistent player identification
  • XR Controllers: Left and right controller position/rotation sync
  • Avatar Visibility: First-person view (own avatar hidden)
  • Camera Tracking: Remote user viewpoint synchronization
  1. Install XR Interaction Toolkit
  2. Configure XR Controllers as “LeftController” and “RightController” Groups
  3. Enable XR Support in realvirtual-XR package
  4. Test Controller Tracking before multiplayer sessions
  • Meta Quest 2/3: Fully tested with Touch controllers
  • Other OpenXR Devices: Compatible through Unity XR system
  • Mixed Reality: Combine VR users with desktop users
  • Change Detection: Only synchronizes data when values change
  • Update Frequency: FixedUpdate (50Hz) for smooth synchronization
  • Interpolation: Client-side smooth movement for controllers
  • Authority Model: Host maintains physics, clients display only
  • Monitor Simultaneous MUs: High MU counts can impact network performance depending on bandwidth
  • Use Appropriate Update Rates: Balance responsiveness with bandwidth (50Hz default)
  • Test Network Conditions: Verify performance under realistic network latency
  • Monitor Connection Quality: Use Unity Profiler for network analysis
  • Unity Transport Configuration: Use default settings for optimal Relay performance
  • Unity Services Authentication: Verify anonymous authentication is enabled in Project Settings → Services
  • Relay Allocation: Check Unity Dashboard for Relay service status and CCU limits
  • Firewall Settings: Ensure UDP traffic is allowed (Unity Transport uses UDP)
  • Join Code Validity: Join codes expire after a timeout period (typically 10 minutes)
  • Package Installation: Verify Unity Netcode for GameObjects is properly installed
  • Network Prefabs: Verify all automation components have corresponding network prefabs
  • Scene Path Resolution: Check that GameObject hierarchy matches between clients
  • Authority Conflicts: Ensure only host modifies authoritative data
  • Physics Conflicts: Verify client MUs are using kinematic rigidbodies
  • Bandwidth Usage: Monitor network traffic in Unity Profiler
  • Update Frequency: Reduce FixedUpdate rate if needed
  • Object Count: Limit number of synchronized objects
  • Connection Stability: Test with realistic network conditions

To synchronize custom automation components:

public class CustomNetworkComponent : NetworkBehaviour
{
[SerializeField] private NetworkVariable<float> customValue = new NetworkVariable<float>();
public override void OnNetworkSpawn()
{
if (IsHost)
{
// Initialize host-controlled values
customValue.Value = GetComponentValue();
}
}
private void FixedUpdate()
{
if (IsHost)
{
// Update network variable when value changes
float newValue = GetComponentValue();
if (Math.Abs(customValue.Value - newValue) > 0.001f)
{
customValue.Value = newValue;
}
}
else
{
// Apply received values on clients
ApplyNetworkValue(customValue.Value);
}
}
}