Overview
When using Unity's Multiplayer Play Mode (MPPM) to test with multiple simultaneous editor instances, each instance needs its own brainCloud identity. Without extra configuration, all instances share the same PlayerPrefs and end up with the same anonymous profile.
The solution is to assign a unique WrapperName to each instance's BrainCloudWrapper. brainCloud prefixes all stored identity data (anonymousId, profileId) with this name, keeping each instance's credentials isolated.
How It Works
Internally, BrainCloudWrapper stores identity in PlayerPrefs using the WrapperName as a prefix:
MPPMPlayer1.brainCloud.profileId → 947ba7df-... MPPMPlayer2.brainCloud.profileId → 3f812c1a-... MPPMPlayer3.brainCloud.profileId → 769e4703-... MPPMPlayer4.brainCloud.profileId → abc12345-...
Each MPPM instance reads its MPPM tag (p1, p2, etc.) at runtime and sets its wrapper name accordingly — so every virtual player authenticates as a separate brainCloud user.
Prerequisites
Unity 6.3+
Multiplayer Play Mode package (
com.unity.multiplayer.playmode) version 2.xbrainCloud Unity SDK installed via Package Manager (
com.bitheads.braincloud)A brainCloud app with App ID and Secret
Step 1 — Install the brainCloud SDK via Package Manager
Open Window → Package Manager
Click + → Add package from git URL
Click Add and wait for the import to complete
The SDK installs with assembly name BrainCloud. Do not fill in credentials in the brainCloud Settings window — you will pass them directly in code.
Step 2 — Add the Assembly Reference
For CurrentPlayer.ReadOnlyTags() to compile in runtime scripts, your .asmdef must reference the MPPM runtime assembly.
Open your .asmdef file and add Unity.Multiplayer.PlayMode.Common.Runtime:
{
"name": "YourProject",
"references": [
"Unity.Multiplayer.PlayMode.Common.Runtime"
]
}
Step 3 — Configure MPPM Play Mode Scenario
Open Window → Multiplayer → Multiplayer Playmode
Click + to create a new scenario
Assign tags for each instance (use lowercase):
Instance | Tag | Role |
Editor (main) |
| Host |
Player 2 |
| Client |
Player 3 |
| Client |
Player 4 |
| Client |
Note: Unity's documentation does not state a hard cap on additional editor instances. In practice, the number may be limited by your machine's available memory and CPU. Keyboard shortcuts in the MPPM window go up to Player 4 (Ctrl+F9–Ctrl+F12), suggesting 4 is the well-tested range.
Step 4 — BCAuthManager Script
Create a BCAuthManager.cs MonoBehaviour that:
Reads the MPPM tag to determine a player index (1–N)
Sets
BrainCloudWrapper.WrapperNameto"MPPMPlayer1","MPPMPlayer2", etc.Calls
Init(url, secret, appId, version)thenAuthenticateAnonymous()
The wrapper is accessed via reflection so the script compiles regardless of how the SDK is installed.
using System;
using UnityEngine;public class BCAuthManager : MonoBehaviour
{
public static BCAuthManager Instance { get; private set; } public string AuthStatus { get; private set; } = "brainCloud: initializing…";
public bool IsAuthenticated { get; private set; } = false;
public string ProfileId { get; private set; } = ""; [SerializeField] private string _appId = "YOUR_APP_ID";
[SerializeField] private string _appSecret = "YOUR_APP_SECRET";
[SerializeField] private string _serverUrl = "https://api.braincloudservers.com/dispatcherv2";
[SerializeField] private string _appVersion = "1.0"; private Component _wrapper;
private int _playerIndex = 0; private System.Reflection.MethodInfo _initMethod;
private System.Reflection.MethodInfo _authAnonMethod;
private System.Reflection.MethodInfo _updateMethod;
private System.Reflection.PropertyInfo _wrapperNameProp;
private System.Reflection.PropertyInfo _clientProp; private void Awake()
{
if (Instance != null && Instance != this) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject); // 1. Detect which MPPM instance this is
_playerIndex = GetMPPMPlayerIndex(); // 2. Locate BrainCloudWrapper (installed via Package Manager)
var wrapperType = Type.GetType("BrainCloudWrapper, BrainCloud")
?? Type.GetType("BrainCloudWrapper, Assembly-CSharp")
?? Type.GetType("BrainCloudWrapper"); if (wrapperType == null)
{
AuthStatus = "brainCloud: SDK not found";
return;
} _wrapper = GetComponent(wrapperType) ?? gameObject.AddComponent(wrapperType);
CacheReflectionMembers(wrapperType); // 3. KEY STEP — unique WrapperName per MPPM instance
if (_wrapperNameProp != null)
_wrapperNameProp.SetValue(_wrapper, "MPPMPlayer" + _playerIndex); Debug.Log("[BCAuthManager] P" + _playerIndex
+ " WrapperName=MPPMPlayer" + _playerIndex); InitAndAuthenticate();
} private void InitAndAuthenticate()
{
if (_wrapper == null || _initMethod == null) return; _initMethod.Invoke(_wrapper,
new object[] { _serverUrl, _appSecret, _appId, _appVersion }); var assembly = _clientProp?.GetValue(_wrapper)?.GetType().Assembly;
var successDelType = assembly?.GetType("BrainCloud.SuccessCallback");
var failureDelType = assembly?.GetType("BrainCloud.FailureCallback"); var onSuccess = successDelType != null
? Delegate.CreateDelegate(successDelType, this, nameof(OnAuthSuccess))
: (Delegate)(Action<string, object>)OnAuthSuccess; var onFailure = failureDelType != null
? Delegate.CreateDelegate(failureDelType, this, nameof(OnAuthFailure))
: (Delegate)(Action<int, int, string, object>)OnAuthFailure; // AuthenticateAnonymous requires 3 args: (success, failure, cbObject)
_authAnonMethod.Invoke(_wrapper, new object[] { onSuccess, onFailure, null });
} private void OnAuthSuccess(string jsonResponse, object cbObject)
{
int idx = jsonResponse.IndexOf("\"profileId\"");
if (idx >= 0)
{
int colon = jsonResponse.IndexOf(':', idx);
int q1 = jsonResponse.IndexOf('"', colon + 1);
int q2 = jsonResponse.IndexOf('"', q1 + 1);
if (q1 >= 0 && q2 > q1)
ProfileId = jsonResponse.Substring(q1 + 1, q2 - q1 - 1);
}
IsAuthenticated = true;
AuthStatus = "brainCloud: OK (P" + _playerIndex + ")";
Debug.Log("[BCAuthManager] P" + _playerIndex
+ " Auth SUCCESS — ProfileId=" + ProfileId);
} private void OnAuthFailure(int status, int reason, string msg, object cbObject)
{
IsAuthenticated = false;
AuthStatus = "brainCloud: FAILED (" + status + "/" + reason + ")";
Debug.LogError("[BCAuthManager] P" + _playerIndex + " Auth FAILED: " + msg);
} private void Update()
{
// brainCloud SDK must be ticked every frame
if (_wrapper != null && _updateMethod != null)
try { _updateMethod.Invoke(_wrapper, null); } catch { }
} private void CacheReflectionMembers(Type wrapperType)
{
var flags = System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public; _initMethod = wrapperType.GetMethod("Init", flags, null,
new[] { typeof(string), typeof(string),
typeof(string), typeof(string) }, null)
?? wrapperType.GetMethod("Init", flags, null,
Type.EmptyTypes, null); _authAnonMethod = wrapperType.GetMethod("AuthenticateAnonymous");
_updateMethod = wrapperType.GetMethod("Update", flags);
_wrapperNameProp = wrapperType.GetProperty("WrapperName");
_clientProp = wrapperType.GetProperty("Client");
} private static int GetMPPMPlayerIndex()
{
#if UNITY_EDITOR
try
{
var tags = Unity.Multiplayer.PlayMode.CurrentPlayer.ReadOnlyTags();
for (int i = 1; i <= 8; i++)
if (System.Array.IndexOf(tags, "p" + i) >= 0)
return i;
}
catch { }
return 0;
#else
return 0;
#endif
}
}
Step 5 — Scene Setup
Create a GameObject named
BrainCloudManagerAdd the
BCAuthManagercomponentFill in App Id and App Secret in the Inspector
BrainCloudWrapper is added automatically at runtime — no manual wiring needed.
Step 6 — Run and Verify
Press Play. Each instance logs its wrapper name and then its unique profile:
[BCAuthManager] P1 WrapperName=MPPMPlayer1 [BCAuthManager] P1 Auth SUCCESS — ProfileId=947ba7df-70a7-4a57-9be5-816f87fa32a2[BCAuthManager] P2 WrapperName=MPPMPlayer2 [BCAuthManager] P2 Auth SUCCESS — ProfileId=3f812c1a-aa01-4b2e-bb33-91d04e7f1234[BCAuthManager] P3 WrapperName=MPPMPlayer3 [BCAuthManager] P3 Auth SUCCESS — ProfileId=769e4703-6d50-40f3-9b39-4f5873b23972
Each ProfileId is unique — confirming that each MPPM instance authenticated as a separate brainCloud user.
Troubleshooting
Symptom | Cause | Fix |
All players get the same | MPPM tags not assigned or wrong case | Assign tags |
| SDK assembly name mismatch | Ensure SDK is installed via Package Manager; code tries |
| Wrong number of arguments | Pass 3 args: |
|
| Use |
Menu | Menu path changed in MPPM 2.x | Use |

