Every peer (player or user connected to an ODIN room) has its own user data. User data within ODIN is always defined
like this:
public byte[] UserData { get; set; }
As you can see, it's just an array of bytes. It's completely up to you how you use this. For example, in simpler games
like casual games, board games, or other forms of multiplayer games that don't need advanced features like movement
prediction, you don't need to use complex multiplayer frameworks like Mirror
Networking or Unity MLAPI to build your game. ODIN's user data is typically enough, as you can link your custom
scripts to the OnPeerUserDataChanged
callback, which is called whenever
user data changes for a connected peer.
If you plan or already use one of those more complex frameworks, you need to sync ODIN with those tools, as in this
case, your players connect to two different servers: the (dedicated) server for the game and ODIN's backend servers for
voice. Don't worry, it's simpler than it seems, as the ODIN SDK does all the heavy lifting for you. In your multiplayer
game, players might be in different teams, and only those teams should be in the same ODIN room. To sync up this
information between ODIN and your game, you can use UserData
.
In our examples, we use a simple class that exposes a simple structure and serializes that to a JSON string that is set
as the peer's user data. Then, "on the other side," this string is serialized back into a class instance.
You'll find this class in the samples folder of the Unity SDK and it
looks
like this:
CustomUserDataJsonFormat implementation
using OdinNative.Odin;
using System;
using System.Text;
using UnityEngine;
namespace OdinNative.Unity.Samples
{
[Serializable]
class CustomUserDataJsonFormat : IUserData
{
public string name;
public string seed;
public string status;
public int muted;
public string user;
public string renderer;
public string platform;
public string revision;
public string version;
public string buildno;
public CustomUserDataJsonFormat() : this("Unity Player", "online") { }
public CustomUserDataJsonFormat(string name, string status)
{
this.name = name;
this.seed = SystemInfo.deviceUniqueIdentifier;
this.status = status;
this.muted = 0;
this.user = string.Format("{0}.{1}", Application.companyName, Application.productName);
this.renderer = Application.unityVersion;
this.platform = string.Format("{0}/{1}", Application.platform, Application.unityVersion);
this.revision = "0";
this.version = Application.version;
this.buildno = Application.buildGUID;
}
public UserData ToUserData()
{
return new UserData(this.ToJson());
}
public static CustomUserDataJsonFormat FromUserData(UserData userData)
{
return JsonUtility.FromJson<CustomUserDataJsonFormat>(userData.ToString());
}
public static bool FromUserData(UserData userData, out CustomUserDataJsonFormat customUserData)
{
try
{
customUserData = JsonUtility.FromJson<CustomUserDataJsonFormat>(userData.ToString());
return true;
}
catch (Exception e)
{
Debug.LogException(e);
customUserData = null;
return false;
}
}
internal string GetAvatarUrl()
{
return string.Format("https://avatars.dicebear.com/api/bottts/{0}.svg?textureChance=0", this.seed);
}
public string ToJson()
{
return JsonUtility.ToJson(this);
}
public override string ToString()
{
return this.ToJson();
}
public byte[] ToBytes()
{
return Encoding.UTF8.GetBytes(this.ToString());
}
}
}
If you like this way of handling user data, copy & paste this code into your own Unity project, rename it to whatever
pleases you (and change the namespace). Then, just use it to set User Data when joining a room:
Using our CustomUserDataJsonFormat
CustomUserDataJsonFormat userData = new CustomUserDataJsonFormat(name, "online");
userData.seed = netId.ToString();
OdinHandler.Instance.JoinRoom("ShooterSample", userData.ToUserData());
Customize the structure to make sense for your own game.
We have a comprehensive guide on how to leverage UserData
to sync up ODIN with a multiplayer game created
with Mirror Networking.