Version: 5.4
Utilizando el API del Transport Layer
Recomendaciones de Networking en Dispositivos Móviles.

Servicios de Internet

Nosotros ofrecemos servicios de Internet que complementan nuestro sistema de networking (red) para soportar su juego a través de su producción y lanzamiento. Esto incluye un servicio de un servidor multi-usuario para permitirle a su juego comunicarse a través de internet. Este proporciona la habilidad para que los usuarios creen partidas y promocionen partidas, listen partidas disponibles y se unan a partidas.

Configurando el servicio Multi-jugador

Antes de que usted pueda utilizar el Matchmaker o los servicios de internet usted necesita registrar el proyecto primero. Vea la Services Window (ventana de servicios) (un icono de una nube en la esquina superior derecha, o vaya a Window->Unity Services en el menú de aplicaciones) dónde el panel multi-jugador debe aparecer. Ahí, usted encontrará un enlace al sitio web multi-jugador en la nube (usted puede también visitar https://multiplayer.unity3d.com directamente). Encuentre el nombre de su proyecto ahí y configure la configuración Multi-jugador.

Recomendación acerca de Unity 5.1.x: El project ID es configurado manualmente en esta versión de Unity, usted puede encontrar el campo para ello en los Player settings (Edit -> Project Settings -> Player). Visite https://multiplayer.unity3d.com y configure su proyecto manualmente y cree una configuración Multi-jugador para ello. Cuando mire la configuración, usted será capaz de ver el ID (se llama UPID ahorita en un formato 12345678–1234–1234–1234–123456789ABC).

Servicio Matchmaking

La característica de networking multi-jugador incluye servicios para que los jugadores jueguen el uno con el otro a través del internet sin necesitar una dirección IP pública. Los usuarios pueden crear juegos, obtener listas de juegos activos y unirse y dejar juegos. Cuando jueguen a través del internet, el trafico de red pasa a través de un relay server alojado por Unity en la nube en vez de uno directo entre los clientes. Esto evita problemas con firewall y NATs, permitiendo que los jugadores se unan desde casi cualquier lugar.

La funcionalidad de matchmaking (emparejamiento de partidas) se puede utilizar con un script especial NetworkMatch, en el namespace UnityEngine.Networking.Match. La habilitad de utilizar un relay server es construido a la LLAPI pero el matchmaker lo hace fácil de usar. Para utilizarlo, derive un script de un NetworkMatch y adjúntelo a un objeto manager. Abajo hay un ejemplo de crear una partida, escuchar por partidas, y unirse a una partida.

using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.Types;
using UnityEngine.Networking.Match;
using System.Collections.Generic;

public class HostGame : MonoBehaviour
{
    List<MatchDesc> matchList = new List<MatchDesc>();
    bool matchCreated;
    NetworkMatch networkMatch;

    void Awake()
    {
        networkMatch = gameObject.AddComponent<NetworkMatch>();
    }

    void OnGUI()
    {
        // You would normally not join a match you created yourself but this is possible here for demonstration purposes.
        if(GUILayout.Button("Create Room"))
        {
            CreateMatchRequest create = new CreateMatchRequest();
            create.name = "NewRoom";
            create.size = 4;
            create.advertise = true;
            create.password = "";

            networkMatch.CreateMatch(create, OnMatchCreate);
        }

        if (GUILayout.Button("List rooms"))
        {
            networkMatch.ListMatches(0, 20, "", OnMatchList);
        }

        if (matchList.Count > 0)
        {
            GUILayout.Label("Current rooms");
        }
        foreach (var match in matchList)
        {
            if (GUILayout.Button(match.name))
            {
                networkMatch.JoinMatch(match.networkId, "", OnMatchJoined);
            }
        }
    }

    public void OnMatchCreate(CreateMatchResponse matchResponse)
    {
        if (matchResponse.success)
        {
            Debug.Log("Create match succeeded");
            matchCreated = true;
            Utility.SetAccessTokenForNetwork(matchResponse.networkId, new NetworkAccessToken(matchResponse.accessTokenString));
            NetworkServer.Listen(new MatchInfo(matchResponse), 9000);
        }
        else
        {
            Debug.LogError ("Create match failed");
        }
    }

    public void OnMatchList(ListMatchResponse matchListResponse)
    {
        if (matchListResponse.success && matchListResponse.matches != null)
        {
            networkMatch.JoinMatch(matchListResponse.matches[0].networkId, "", OnMatchJoined);
        }
    }

    public void OnMatchJoined(JoinMatchResponse matchJoin)
    {
        if (matchJoin.success)
        {
            Debug.Log("Join match succeeded");
            if (matchCreated)
            {
                Debug.LogWarning("Match already set up, aborting...");
                return;
            }
            Utility.SetAccessTokenForNetwork(matchJoin.networkId, new NetworkAccessToken(matchJoin.accessTokenString));
            NetworkClient myClient = new NetworkClient();
            myClient.RegisterHandler(MsgType.Connect, OnConnected);
            myClient.Connect(new MatchInfo(matchJoin));
        }
        else
        {
            Debug.LogError("Join match failed");
        }
    }

    public void OnConnected(NetworkMessage msg)
    {
        Debug.Log("Connected!");
    }
}

Este script configura el matchmaker a que apunte al servidor público unity matchmaker. Llama las funciones de la clase base para crear, escuchar, y unirse a partidas. CreateMatch para crear una partida, JoinMatch para unirse a una partida, y ListMatches para escuchar por partidas registradas en el servidor matchmaker. Internamente, el NetworkMatch utiliza servicios web para establecer una partida y la función callback dada es invocada cuando el proceso se haya completad, como OnMatchCreate para la creación de una partida.

Para utilizar un relay server en vez de una conexión directa, usted debe poblar el singleton NetworkMatch.matchSingleton. Esto le dice al sistema que utilice el relay server en vez de una conexión directa cuando se conecte al juego. Entonces después, cuando el cliente en realidad se conecte al juego, este automáticamente utilizará el relay server adecuado para la partida que fue escogida.

Relay server

El relay server trabaja de cerca con el servidor matchmaker, como se menciono arriba. Las clases de más alto nivel manejan el relay para usted automáticamente. No hay mucho trabajo extra para que usted haga. Aquí, sin embargo, hay un ejemplo que muestra cómo usted puede utilizar el matchmaker y el relay server a través del transport layer de bajo nivel utilizando la clase NetworkTransport directamente.

using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.Types;
using UnityEngine.Networking.Match;
using System.Collections.Generic;

public class SimpleSetup : MonoBehaviour
{
    // Matchmaker related
    List<MatchDesc> m_MatchList = new List<MatchDesc>();
    bool m_MatchCreated;
    bool m_MatchJoined;
    MatchInfo m_MatchInfo;
    string m_MatchName = "NewRoom";
    NetworkMatch m_NetworkMatch;

    // Connection/communication related
    int m_HostId = -1;
    // On the server there will be multiple connections, on the client this will only contain one ID
    List<int> m_ConnectionIds = new List<int>();
    byte[] m_ReceiveBuffer;
    string m_NetworkMessage = "Hello world";
    string m_LastReceivedMessage = "";
    NetworkWriter m_Writer;
    NetworkReader m_Reader;
    bool m_ConnectionEstablished;

    const int k_ServerPort = 25000;
    const int k_MaxMessageSize = 65535;

    void Awake()
    {
        m_NetworkMatch = gameObject.AddComponent<NetworkMatch>();
    }

    void Start()
    {
        m_ReceiveBuffer = new byte[k_MaxMessageSize];
        m_Writer = new NetworkWriter();
        // While testing with multiple standalone players on one machine this will need to be enabled
        Application.runInBackground = true;
    }

    void OnApplicationQuit()
    {
        NetworkTransport.Shutdown();
    }

    void OnGUI()
    {
        if (string.IsNullOrEmpty(Application.cloudProjectId))
            GUILayout.Label("You must set up the project first. See the Multiplayer tab in the Service Window");
        else
            GUILayout.Label("Cloud Project ID: " + Application.cloudProjectId);

        if (m_MatchJoined)
            GUILayout.Label("Match joined '" + m_MatchName + "' on Matchmaker server");
        else if (m_MatchCreated)
            GUILayout.Label("Match '" + m_MatchName + "' created on Matchmaker server");

        GUILayout.Label("Connection Established: " + m_ConnectionEstablished);

        if (m_MatchCreated || m_MatchJoined)
        {
            GUILayout.Label("Relay Server: " + m_MatchInfo.address + ":" + m_MatchInfo.port);
            GUILayout.Label("NetworkID: " + m_MatchInfo.networkId + " NodeID: " + m_MatchInfo.nodeId);
            GUILayout.BeginHorizontal();
            GUILayout.Label("Outgoing message:");
            m_NetworkMessage = GUILayout.TextField(m_NetworkMessage);
            GUILayout.EndHorizontal();
            GUILayout.Label("Last incoming message: " + m_LastReceivedMessage);

            if (m_ConnectionEstablished && GUILayout.Button("Send message"))
            {
                m_Writer.SeekZero();
                m_Writer.Write(m_NetworkMessage);
                byte error;
                for (int i = 0; i < m_ConnectionIds.Count; ++i)
                {
                    NetworkTransport.Send(m_HostId, 
                        m_ConnectionIds[i], 0, m_Writer.AsArray(), m_Writer.Position, out error);
                    if ((NetworkError)error != NetworkError.Ok)
                        Debug.LogError("Failed to send message: " + (NetworkError)error);
                }
            }

            if (GUILayout.Button("Shutdown"))
            {
                m_NetworkMatch.DropConnection(m_MatchInfo.networkId, 
                    m_MatchInfo.nodeId, OnConnectionDropped);
            }
        }
        else
        {
            if (GUILayout.Button("Create Room"))
            {
                m_NetworkMatch.CreateMatch(m_MatchName, 4, true, "", OnMatchCreate);
            }

            if (GUILayout.Button("Join first found match"))
            {
                m_NetworkMatch.ListMatches(0, 1, "", (response) => {
                    if (response.success && response.matches.Count > 0)
                        m_NetworkMatch.JoinMatch (response.matches [0].networkId, "", OnMatchJoined);   
                });
            }
                
            if (GUILayout.Button ("List rooms"))
            {
                m_NetworkMatch.ListMatches (0, 20, "", OnMatchList);
            }

            if (m_MatchList.Count > 0)
            {
                GUILayout.Label ("Current rooms:");
            }
            foreach (var match in m_MatchList) 
            {
                if (GUILayout.Button (match.name))
                {
                    m_NetworkMatch.JoinMatch(match.networkId, "", OnMatchJoined);
                }
            }
        }
    }

    public void OnConnectionDropped(BasicResponse callback)
    {
        Debug.Log("Connection has been dropped on matchmaker server");
        NetworkTransport.Shutdown();
        m_HostId = -1;
        m_ConnectionIds.Clear();
        m_MatchInfo = null;
        m_MatchCreated = false;
        m_MatchJoined = false;
        m_ConnectionEstablished = false;
    }

    public void OnMatchCreate(CreateMatchResponse matchResponse)
    {
        if (matchResponse.success)
        {
            Debug.Log("Create match succeeded");
            Utility.SetAccessTokenForNetwork(matchResponse.networkId, 
                new NetworkAccessToken(matchResponse.accessTokenString));

            m_MatchCreated = true;
            m_MatchInfo = new MatchInfo(matchResponse);

            StartServer(matchResponse.address, matchResponse.port, matchResponse.networkId, 
                matchResponse.nodeId);
        }
        else
        {
            Debug.LogError ("Create match failed");
        }
    }

    public void OnMatchList(ListMatchResponse matchListResponse)
    {
        if (matchListResponse.success && matchListResponse.matches != null)
        {
            m_MatchList = matchListResponse.matches;
        }
    }

    // When we've joined a match we connect to the server/host
    public void OnMatchJoined(JoinMatchResponse matchJoin)
    {
        if (matchJoin.success)
        {
            Debug.Log("Join match succeeded");
            Utility.SetAccessTokenForNetwork(matchJoin.networkId, 
                new NetworkAccessToken(matchJoin.accessTokenString));

            m_MatchJoined = true;
            m_MatchInfo = new MatchInfo(matchJoin);

            Debug.Log ("Connecting to Address:" + matchJoin.address + 
                " Port:" + matchJoin.port + 
                " NetworKID: " + matchJoin.networkId + 
                " NodeID: " + matchJoin.nodeId);
            ConnectThroughRelay(matchJoin.address, matchJoin.port, matchJoin.networkId, 
                matchJoin.nodeId);
        }
        else
        {
            Debug.LogError("Join match failed");
        }
    }

    void SetupHost(bool isServer)
    {
        Debug.Log("Initializing network transport");
        NetworkTransport.Init();
        var config = new ConnectionConfig();
        config.AddChannel(QosType.Reliable);
        config.AddChannel(QosType.Unreliable);
        var topology = new HostTopology(config, 4);
        if (isServer)
            m_HostId = NetworkTransport.AddHost(topology, k_ServerPort);
        else
            m_HostId = NetworkTransport.AddHost(topology);
    }

    void StartServer(string relayIp, int relayPort, NetworkID networkId, NodeID nodeId)
    {
        SetupHost(true);

        byte error;
        NetworkTransport.ConnectAsNetworkHost(
            m_HostId, relayIp, relayPort, networkId, Utility.GetSourceID(), nodeId, out error);
    }

    void ConnectThroughRelay(string relayIp, int relayPort, NetworkID networkId, NodeID nodeId)
    {
        SetupHost(false);

        byte error;
        NetworkTransport.ConnectToNetworkPeer(
            m_HostId, relayIp, relayPort, 0, 0, networkId, Utility.GetSourceID(), nodeId, out error);
    }

    void Update()
    {
        if (m_HostId == -1)
            return;

        var networkEvent = NetworkEventType.Nothing;
        int connectionId;
        int channelId;
        int receivedSize;
        byte error;

        // Get events from the relay connection
        networkEvent = NetworkTransport.ReceiveRelayEventFromHost (m_HostId, out error);
        if (networkEvent == NetworkEventType.ConnectEvent)
            Debug.Log ("Relay server connected");
        if (networkEvent == NetworkEventType.DisconnectEvent)
            Debug.Log ("Relay server disconnected");

        do
        {
            // Get events from the server/client game connection
            networkEvent = NetworkTransport.ReceiveFromHost(m_HostId, out connectionId, out channelId, 
                m_ReceiveBuffer, (int)m_ReceiveBuffer.Length, out receivedSize, out error);
            if ((NetworkError)error != NetworkError.Ok)
            {
                Debug.LogError("Error while receiveing network message: " + (NetworkError)error);
            }

            switch (networkEvent)
            {
                case NetworkEventType.ConnectEvent:
                {
                    Debug.Log("Connected through relay, ConnectionID:" + connectionId + 
                        " ChannelID:" + channelId);
                    m_ConnectionEstablished = true;
                    m_ConnectionIds.Add(connectionId);
                    break;
                }
                case NetworkEventType.DataEvent:
                {
                    Debug.Log("Data event, ConnectionID:" + connectionId + 
                        " ChannelID: " + channelId +
                        " Received Size: " + receivedSize);
                    m_Reader = new NetworkReader(m_ReceiveBuffer);
                    m_LastReceivedMessage = m_Reader.ReadString();
                    break;
                }
                case NetworkEventType.DisconnectEvent:
                {
                    Debug.Log("Connection disconnected, ConnectionID:" + connectionId);
                    break;
                }
                case NetworkEventType.Nothing:
                break;
            }
        } while (networkEvent != NetworkEventType.Nothing);
    }
}
Utilizando el API del Transport Layer
Recomendaciones de Networking en Dispositivos Móviles.