Voltar para o Blog
Quest Log

Mirror no Unity: networking open source

Vários computadores ligados a um servidor central por linhas de luz formando um espelho de conexões

Mirror Unity multiplayer: instale o fork open source do UNet, use NetworkManager, SyncVar, Command e ClientRpc, faça spawn de jogadores e escolha entre Mirror, Photon e Netcode.

Ferramenta:UnityC#

Fazer mirror unity multiplayer é a escolha de quem quer networking de verdade sem pagar por conexão. O Mirror é um fork open source do antigo UNet da Unity, mantido pela comunidade sob licença MIT. Em vez de um serviço na nuvem que cobra por usuário simultâneo, o Mirror te dá o código completo: você roda o servidor onde quiser, seja na máquina de um dos jogadores (host) ou num servidor dedicado na nuvem. Nada de taxa por CCU, nada de caixa-preta.

Este tutorial monta o essencial no Unity: instalar o Mirror, usar o NetworkManager com o HUD pronto, escrever um NetworkBehaviour, sincronizar estado com [SyncVar], mandar ação do cliente para o servidor com [Command] e do servidor para os clientes com [ClientRpc], fazer spawn de jogadores e entender host contra server mais client. No fim, comparo Mirror com Photon e com o Netcode nativo para você escolher com critério. Todo o código é C# real e compilável.

Mirror Unity multiplayer: o modelo servidor-autoritativo

O Mirror parte de uma ideia firme: o servidor manda. Existe uma cópia do jogo que é a verdade, e os clientes pedem coisas a ela. Isso é o oposto do modelo em que cada jogador decide sozinho e confia nos outros.

Na prática, há três modos de rodar o mesmo projeto:

  • Host: uma máquina roda o servidor e um cliente juntos. É o jogador que "abre a sala". Comum em co-op entre amigos.
  • Server: só a parte servidora, sem jogador e sem janela (build headless). É o que você sobe num servidor dedicado na nuvem.
  • Client: quem só conecta num servidor que já existe.

A beleza é que o mesmo código atende os três. Você escreve uma vez e decide o modo na hora de rodar. Se os conceitos de host e cliente ainda são novos para você, comece pelo post de como fazer jogo multiplayer na Unity e volte, porque o Mirror assume que você já entende essa divisão.

Instalar o Mirror

O Mirror está na Asset Store como pacote gratuito. Procure por Mirror, adicione à conta e importe pelo Package Manager (aba My Assets). A comunidade também distribui pelo repositório no GitHub, mas pela Asset Store o update é mais simples.

Depois de importar, o Mirror pede para reiniciar o editor na primeira vez, porque ele troca componentes internos. Deixe reiniciar. Pronto: nenhum App ID, nenhuma conta, nenhum login. Diferente do Photon, não existe passo de dashboard, porque não há serviço na nuvem no meio.

NetworkManager e o HUD

O coração do Mirror é o NetworkManager. Ele cuida de subir o servidor, conectar clientes, trocar de cena e spawnar o jogador.

  1. Crie um objeto vazio na cena e chame de NetworkManager.
  2. Adicione o componente NetworkManager.
  3. Adicione também o KCP Transport (vem junto com o Mirror). O Transport é a camada que de fato manda os bytes pela rede; o KCP é o padrão, feito sobre UDP, com boa latência para jogo.
  4. Adicione o Network Manager HUD. Ele desenha na tela três botões: Host, Server e Client.

Rode a cena e você vê o HUD. Clique em Host (server + client) para testar sozinho. Numa segunda build (ou outra máquina), clique em Client apontando para o IP do host. O HUD é feio de propósito: serve para testar rápido, e você troca por um menu de verdade depois.

No NetworkManager, o campo Player Prefab aponta o objeto que representa cada jogador. Esse prefab precisa de um componente NetworkIdentity, que é o que dá a ele um dono e um ID de rede. Sem NetworkIdentity, o Mirror ignora o objeto.

NetworkBehaviour, SyncVar e autoridade

No single player, um script é MonoBehaviour. No Mirror, scripts que vivem em rede herdam de NetworkBehaviour. Ele traz duas informações que você usa o tempo todo: isServer (este código está rodando no servidor?) e isLocalPlayer (este objeto é o jogador desta máquina?).

O jeito mais simples de manter um valor igual em todos é o [SyncVar]. Você escreve a variável só no servidor, e o Mirror propaga a mudança para todos os clientes sozinho.

using Mirror;
using UnityEngine;

public class VidaJogador : NetworkBehaviour
{
    // O servidor escreve; todos os clientes recebem o valor atualizado.
    [SyncVar(hook = nameof(AoMudarVida))]
    private int vida = 100;

    // Hook roda em cada cliente quando a vida muda.
    private void AoMudarVida(int valorAntigo, int valorNovo)
    {
        Debug.Log("Vida agora: " + valorNovo);
        // Aqui você atualizaria a barra de vida na tela.
    }

    [Server]
    public void LevarDano(int quantidade)
    {
        vida -= quantidade;
        if (vida <= 0)
        {
            vida = 0;
            Debug.Log("Jogador morreu (decidido no servidor).");
        }
    }
}

O atributo [Server] garante que LevarDano só roda no servidor; se um cliente tentar chamar, o Mirror avisa e bloqueia. O hook dispara a função AoMudarVida em cada cliente quando o valor chega, que é onde você mexe na interface. A regra de ouro: estado que importa (vida, pontos, posição oficial) é escrito só no servidor.

Command: do cliente para o servidor

O cliente não escreve no estado do jogo direto. Ele pede ao servidor com um [Command]: um método que o cliente chama mas que executa no servidor.

using Mirror;
using UnityEngine;

public class AtaqueJogador : NetworkBehaviour
{
    [SerializeField] private int danoPorTiro = 25;

    private void Update()
    {
        // Só o dono deste objeto lê o input.
        if (!isLocalPlayer) return;

        if (Input.GetButtonDown("Fire1"))
        {
            CmdAtirar();
        }
    }

    // Nome começa com "Cmd" por convenção obrigatória do Mirror.
    [Command]
    private void CmdAtirar()
    {
        // Este corpo roda no servidor, não no cliente que clicou.
        Debug.Log("Servidor processou um tiro.");
        RpcMostrarTiro();
    }

    // ClientRpc: servidor manda todos os clientes mostrarem o efeito.
    [ClientRpc]
    private void RpcMostrarTiro()
    {
        Debug.Log("Efeito de tiro aparece em todos os clientes.");
    }
}

Repare na convenção: métodos [Command] começam com Cmd e métodos [ClientRpc] começam com Rpc. O Mirror exige esses prefixos e o build falha sem eles. O fluxo é: o jogador clica, o cliente chama CmdAtirar, o corpo roda no servidor, o servidor valida (munição, cooldown, linha de tiro) e só então chama RpcMostrarTiro para avisar todo mundo. O cliente nunca aplica dano por conta própria.

Entender esse ida e volta é o divisor de águas do multiplayer. Conectar dois personagens na tela qualquer tutorial mostra. O que quase nenhum mostra é o resto: decidir quem tem autoridade sobre cada coisa, validar ações no servidor para ninguém trapacear, tratar o jogador que cai no meio da partida e amarrar isso num jogo com menu, fases e placar. Multiplayer multiplica o trabalho de cada sistema, e é onde quem aprende sozinho mais costuma travar.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

ClientRpc: do servidor para os clientes

Se o [Command] é o cliente pedindo, o [ClientRpc] é o servidor respondendo para todos. Serve para efeitos e eventos que todo mundo precisa ver ao mesmo tempo: um tiro, uma explosão, um portão que abre, o placar que muda.

No exemplo acima, RpcMostrarTiro roda em todos os clientes conectados. Existe também o [TargetRpc], que manda a mensagem para um cliente só (útil para avisar "você pegou um item" apenas a quem pegou). A diferença entre as três chamadas resume o modelo inteiro:

  • [Command]: cliente para servidor (pedir).
  • [ClientRpc]: servidor para todos os clientes (avisar todo mundo).
  • [TargetRpc]: servidor para um cliente específico (avisar um só).

Guarde a regra: cliente pede com Command, servidor confirma e avisa com Rpc. Para movimento contínuo (posição a cada frame), não se usa Rpc no braço, e sim o componente NetworkTransform, que o Mirror já traz pronto. Como configurar sincronização de movimento com cuidado está no post sobre NetworkTransform e sincronizar movimento.

Spawn de jogadores e objetos

O NetworkManager já spawna o Player Prefab para cada cliente que conecta, usando o campo Player Prefab que você preencheu. Para escolher onde cada um nasce, espalhe objetos com o componente NetworkStartPosition pela cena e ponha o Player Spawn Method do NetworkManager em Round Robin ou Random. Ele distribui os jogadores por esses pontos sozinho.

Para objetos que não são jogador (um projétil, um inimigo, um item dropado), há dois passos:

  1. Registre o prefab na lista Registered Spawnable Prefabs do NetworkManager (ou pela API NetworkClient.RegisterPrefab). O prefab precisa de NetworkIdentity.
  2. No servidor, crie com Instantiate normal e depois chame NetworkServer.Spawn para o objeto existir em todos os clientes.
using Mirror;
using UnityEngine;

public class SpawnInimigo : NetworkBehaviour
{
    [SerializeField] private GameObject prefabInimigo;

    [Server]
    public void CriarInimigo(Vector3 pos)
    {
        GameObject inimigo = Instantiate(prefabInimigo, pos, Quaternion.identity);
        // Sem esta linha, o inimigo só existe no servidor.
        NetworkServer.Spawn(inimigo);
    }
}

O NetworkServer.Spawn é o equivalente Mirror do que o Photon faz no PhotonNetwork.Instantiate: ele não só cria, mas replica o objeto para todos e amarra o NetworkIdentity. Esquecer essa chamada é o erro número um de quem está começando: o inimigo aparece no host e some para os clientes.

Mirror, Photon ou Netcode nativo

Os três resolvem multiplayer na Unity, mas com trocas diferentes.

  • Mirror é open source, gratuito de licença e feito para você hospedar, inclusive servidor dedicado headless. Dá controle total e modelo servidor-autoritativo limpo, bom contra trapaça. O custo é que você cuida da hospedagem e da camada de matchmaking, que não vem pronta. Para o passo a passo de usar o Photon no lugar, veja o post sobre Photon no Unity com PUN 2.
  • Photon (PUN/Fusion) tira você do zero mais rápido porque o servidor roda no Photon Cloud e o matchmaking vem pronto. O custo é a precificação por usuário simultâneo e depender de um serviço externo.
  • Netcode for GameObjects, o nativo da Unity, integra com Relay e Lobby dos serviços Unity e é mantido pela própria engine. Fica no meio: menos montagem que Mirror para conexão pela internet, mais acoplado ao ecossistema Unity.

Uma heurística honesta: para jogo competitivo que precisa de servidor dedicado e defesa contra trapaça, o Mirror brilha. Para co-op entre amigos que você quer no ar rápido, Photon ou Relay entregam antes. Para comparar os caminhos de infraestrutura lado a lado, o post sobre backend para jogo multiplayer: opções abre as contas.

Próximo passo

Faça o teste mínimo hoje: uma build de host e o editor como client, os dois conectando no mesmo jogo, e um [Command] disparando um [ClientRpc] que aparece nos dois. Quando isso rodar, você entendeu o núcleo do Mirror, e o resto (vida com SyncVar, spawn de inimigos, menu no lugar do HUD) é repetição desse padrão. O servidor manda, o cliente pede, e o estado flui numa direção só. Essa disciplina é o que separa o protótipo que trava do jogo que aguenta gente de verdade.

Perguntas frequentes

Mirror é gratuito mesmo?

Sim. O Mirror é open source sob licença MIT e não cobra por CCU nem por banda. O custo que sobra é o do servidor: como você mesmo hospeda, paga a máquina que roda o jogo (ou nada, se o host for um dos jogadores). Não há taxa do Mirror em si.

Qual a diferença entre host, server e client no Mirror?

Host é um jogador que roda o servidor e o cliente na mesma máquina ao mesmo tempo, comum em co-op entre amigos. Server é só a parte servidora, sem jogador, usada em servidor dedicado na nuvem. Client é quem só conecta num servidor existente. O mesmo projeto Mirror atende os três modos.

Mirror serve para servidor dedicado?

Sim, e é um dos motivos de escolher Mirror. Você faz uma build de servidor (sem gráficos, modo headless) e sobe numa máquina na nuvem. O servidor tem autoridade sobre o jogo, o que reduz trapaça. É mais trabalho que uma solução de host, mas é o caminho para jogo competitivo.

Qual a diferença entre Command e ClientRpc?

Command é um método que o cliente chama mas que roda no servidor (do jogador para o servidor), usado para pedir uma ação. ClientRpc é um método que o servidor chama e que roda em todos os clientes (do servidor para os jogadores), usado para avisar o que aconteceu. A regra é: cliente pede com Command, servidor confirma e avisa com ClientRpc.