Developer Documentation

Understanding User Data

Every peer (players 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. ODINs 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 ODINs backend servers for voice. Don’t worry, it’s simpler than it seems as 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 these 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 peers 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 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
// Generate a JSON User Data object with the players netId and name in the network
CustomUserDataJsonFormat userData = new CustomUserDataJsonFormat(name, "online");
userData.seed = netId.ToString();

// Join ODIN Room ShooterSample and send user data
OdinHandler.Instance.JoinRoom("ShooterSample", userData.ToUserData());

Customize the structure that makes 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 .