🎮 UnityDocs

Multiplayer con Steam: lobbies y P2P

Cómo usar la plataforma de Steam para el multiplayer: lobbies, invitaciones de amigos y su red P2P con relay, combinada con Mirror o Netcode. Qué librería usar y qué necesitas para probar y publicar.

📄 ArtículoAvanzado✅ RevisadoUnity 6.0 LTSActualizado 2026-07-15
DificultadConceptual Código Matemáticas
Tiempo📖 Lectura 9 min · ⌨️ Práctica 40 min

Steam no es un netcode: es una plataforma#

Steam no sustituye a Netcode o Mirror: los complementa. Lo que aporta:

  • Lobbies: salas para reunir jugadores antes de la partida.
  • Amigos e invitaciones: unirse a la partida de un amigo desde el overlay de Steam.
  • Red P2P con relay (SDR): conecta a los jugadores sin abrir puertos ni compartir IP, enrutando por los servidores de Valve. Gratis para desarrolladores de Steam.

La arquitectura típica: tu framework de red (Mirror/NGO) hace la lógica, y Steam es el transporte + el sistema de lobbies.

Qué librería usar

Para hablar con la API de Steam desde C# tienes dos envoltorios: Steamworks.NET (fino, pegado a la API de C++) y Facepunch.Steamworks (más moderno y cómodo en C#, con async/await). Los ejemplos de aquí usan Facepunch. Para el transporte con Mirror, el más usado es FizzySteamworks.

Requisitos para probar#

Necesitas el cliente de Steam abierto

Para que la API funcione: el cliente de Steam debe estar ejecutándose y logueado, y tu proyecto necesita un archivo steam_appid.txt en la raíz con el App ID. Para pruebas se usa el App ID 480 (Spacewar, el juego de ejemplo de Valve). Publicar de verdad requiere una cuenta Steamworks (100 $ una vez) y tu propio App ID.

Inicializar Steam#

C#
using Steamworks;   // Facepunch.Steamworks
using UnityEngine;

public class SteamGestor : MonoBehaviour
{
    void Awake()
    {
        try
        {
            SteamClient.Init(480);   // 480 = Spacewar (pruebas)
            Debug.Log("Steam listo. Jugador: " + SteamClient.Name);
        }
        catch (System.Exception e)
        {
            Debug.LogError("No se pudo iniciar Steam: " + e.Message);
        }
    }

    void Update() => SteamClient.RunCallbacks();   // procesar eventos de Steam

    void OnApplicationQuit() => SteamClient.Shutdown();
}

Crear y unirse a un lobby#

C#
using System.Threading.Tasks;
using Steamworks;
using Steamworks.Data;
using UnityEngine;

public class LobbySteam : MonoBehaviour
{
    public async Task CrearLobby()
    {
        // Sala para 4 jugadores
        Lobby? lobby = await SteamMatchmaking.CreateLobbyAsync(4);
        if (lobby.HasValue)
        {
            lobby.Value.SetPublic();
            lobby.Value.SetData("nombre", "Partida de " + SteamClient.Name);
            Debug.Log("Lobby creado: " + lobby.Value.Id);
        }
    }

    void OnEnable()
    {
        // El jugador acepta una invitación desde el overlay de Steam
        SteamMatchmaking.OnLobbyEntered += LobbyEntrado;
        SteamFriends.OnGameLobbyJoinRequested += UnirseDesdeInvitacion;
    }

    void OnDisable()
    {
        SteamMatchmaking.OnLobbyEntered -= LobbyEntrado;
        SteamFriends.OnGameLobbyJoinRequested -= UnirseDesdeInvitacion;
    }

    void LobbyEntrado(Lobby lobby)
    {
        Debug.Log("Has entrado al lobby: " + lobby.Id);
        // Aquí arrancas tu red (host si eres el dueño, cliente si no)
    }

    async void UnirseDesdeInvitacion(Lobby lobby, SteamId id)
    {
        await lobby.Join();
    }
}
El lobby conecta, la red juega

El flujo habitual: el host crea el lobby y arranca su servidor (Mirror/NGO); los invitados entran al lobby, leen la SteamId del host y se conectan a él mediante el transporte de Steam. El lobby es la "sala de espera"; la partida la lleva tu framework de red.

Combinarlo con tu framework#

  • Con Mirror: instala el transporte FizzySteamworks y ponlo como Transport del NetworkManager. Mirror mandará sus mensajes por la red P2P de Steam en vez de por IP.
  • Con Netcode for GameObjects: existen transportes de comunidad (basados en Facepunch o Steamworks.NET) que hacen el mismo papel para NGO.

Así tu código de red no cambia: solo cambias por dónde viajan los bytes.

Cuándo usar Steam#

🧭 ¿Qué debería usar?
  • ¿Publicas en Steam y quieres invitaciones de amigos y "unirse a partida"? → sí, Steam
  • ¿Quieres P2P sin abrir puertos ni pagar servidores? → sí, la red de Steam (SDR) lo da gratis
  • ¿Tu juego no sale en Steam (móvil, web)? → no; usa Relay de Unity, Photon, etc.
  • ¿Aún estás aprendiendo la red? → primero haz que funcione en LAN; añade Steam al final

Errores frecuentes#

  • Probar sin el cliente de Steam abierto o sin steam_appid.txt (la init falla).
  • Olvidar SteamClient.RunCallbacks() cada frame (los eventos no llegan).
  • No llamar a SteamClient.Shutdown() al salir.
  • Intentar meter Steam antes de que el juego funcione en LAN: depura una capa cada vez.
  • Creer que Steam sustituye al netcode (sigue necesitando Mirror/NGO para la lógica).

Ponte a prueba#

📝 Pon a prueba lo aprendido

Resumen#

Steam es plataforma + transporte, no un netcode: aporta lobbies, invitaciones de amigos y P2P con relay (sin abrir puertos), y se combina con Mirror (FizzySteamworks) o NGO. Usa Facepunch.Steamworks o Steamworks.NET, ten el cliente de Steam abierto con steam_appid.txt (480 para pruebas), inicializa con SteamClient.Init, llama a RunCallbacks cada frame, y añade Steam cuando el juego ya funcione en LAN. Elige según tu caso en la comparativa.

Fuentes y para profundizar