Voltar para o Blog
Quest Log

Autoridade de Servidor no Godot Multiplayer (Anti-Trapaça)

Diagrama de um servidor Godot ao centro recebendo input de vários clientes e devolvendo o estado validado do jogo

Autoridade de servidor no Godot multiplayer: set_multiplayer_authority, modelo servidor-autoritativo e por que validar o input para evitar trapaça.

Ferramenta:Godot

Se você já montou o básico de rede e agora alguém consegue "andar" pela parede ou aparecer com vida infinita, o assunto que falta é autoridade de servidor no Godot multiplayer. Autoridade é a resposta para a pergunta "quem tem o direito de decidir o estado deste objeto?", e é a diferença entre um jogo que resiste a trapaça e um que qualquer cliente modificado desmonta. Neste post a gente aprofunda o conceito: o que é autoridade por node, como usar set_multiplayer_authority, get_multiplayer_authority e is_multiplayer_authority, a diferença entre o modelo servidor-autoritativo e o cliente-autoritativo, por que o servidor precisa validar o input, e o padrão em que cada cliente tem autoridade só sobre o próprio input.

Este é um aprofundamento. Se os termos @rpc, rpc_id e MultiplayerPeer ainda soam novos, vale primeiro passar pelo multiplayer no Godot com RPC, que monta a conexão do zero. Aqui a gente parte do princípio de que você já tem duas máquinas conversando e quer que essa conversa seja confiável.

O que é autoridade, de fato

No sistema de rede high-level da Godot, todo node tem uma autoridade: um peer (identificado por um id numérico) que é considerado o dono daquele node. A autoridade é quem pode, por exemplo, mandar os valores de um MultiplayerSynchronizer para os outros, e quem pode disparar RPCs marcadas com o modo authority.

Por padrão, a autoridade de qualquer node é o id 1, que é sempre o servidor/host. Ou seja, num projeto recém-criado, o servidor manda em tudo. Isso já é o começo de um desenho saudável.

Três funções formam o núcleo da API:

  • set_multiplayer_authority(id: int, recursive: bool = true): define qual peer é dono do node. O recursive (ligado por padrão) propaga a autoridade para os nodes filhos também.
  • get_multiplayer_authority() -> int: retorna o id do peer que é dono daquele node, naquela máquina.
  • is_multiplayer_authority() -> bool: atalho que retorna true se o peer local é a autoridade do node. É o que você mais usa no dia a dia.

Um detalhe crucial: is_multiplayer_authority() responde de forma diferente em cada máquina. O mesmo node de jogador existe em todas as telas, mas is_multiplayer_authority() só devolve true na máquina que de fato manda nele. É exatamente isso que permite escrever um script que roda em todo mundo mas só age onde deve:

extends CharacterBody2D

func _physics_process(delta: float) -> void:
    # so a maquina dona deste personagem le o teclado dele
    if not is_multiplayer_authority():
        return
    var direcao: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    velocity = direcao * 200.0
    move_and_slide()

Esse if not is_multiplayer_authority(): return é o padrão mais repetido em código de rede na Godot. Ele garante que cada máquina só processe o input de quem ela controla, e não fique tentando mover os personagens dos outros.

Definindo a autoridade por node

A autoridade não é global, é por node. Isso é poderoso: o personagem do jogador 2 pode ter o jogador 2 como autoridade, enquanto os inimigos e o placar continuam com o servidor. A definição costuma acontecer no momento em que o jogador nasce na cena.

O ponto delicado é que set_multiplayer_authority precisa ser chamado de forma determinística em todas as máquinas, para que todas concordem sobre quem é o dono. Um jeito comum e seguro é usar o próprio nome do node como o id do peer dono:

# ao instanciar o personagem, nomeie-o com o id do peer dono
var jogador := CENA_JOGADOR.instantiate()
jogador.name = str(id_do_peer)
contei_jogadores.add_child(jogador)

# dentro do script do jogador, no _enter_tree:
func _enter_tree() -> void:
    var id_dono: int = str(name).to_int()
    set_multiplayer_authority(id_dono)

Como o MultiplayerSpawner replica o node com o mesmo nome em todas as telas, o _enter_tree roda em cada máquina e todas chegam ao mesmo id_dono. Ninguém precisa mandar uma RPC extra só para combinar quem manda: o nome do node já carrega essa informação.

Quer conferir quem é o dono em tempo de execução? get_multiplayer_authority() responde. É útil em logs de depuração, quando você está caçando aquele bug clássico de "duas máquinas discordando sobre quem controla o quê".

Servidor-autoritativo x cliente-autoritativo

Aqui mora a decisão de arquitetura mais importante do seu multiplayer. Existem dois modelos, e a escolha define o quanto o seu jogo resiste a trapaça.

No modelo cliente-autoritativo, cada cliente é a autoridade sobre o próprio personagem. O cliente decide sua posição, sua vida, e simplesmente informa os outros ("estou aqui, com tanta vida"). É simples de implementar, dá resposta instantânea, e funciona bem quando os jogadores confiam uns nos outros. O problema é óbvio quando existe competição: o cliente roda na máquina do jogador, e a máquina do jogador pode ser modificada. Se o cliente diz "minha vida é 9999" e o resto acredita, acabou a graça.

No modelo servidor-autoritativo, o servidor é a fonte da verdade sobre o estado do jogo. O cliente não decide sua posição real nem sua vida; ele manda a intenção de input ("quero andar para a direita", "apertei o botão de atirar") e o servidor processa, valida e devolve o estado oficial. É mais trabalhoso, adiciona latência (o round-trip até o servidor e de volta) e exige técnicas como predição para parecer responsivo, mas é o único modelo que aguenta jogadores com incentivo para trapacear.

A escolha honesta é por risco. Coop PvE entre amigos? Cliente-autoritativo pode ser suficiente e muito mais barato de construir. PvP ranqueado, com placar que importa? Servidor-autoritativo não é opcional. Não copie a arquitetura de um FPS competitivo para o seu jogo de fazenda coop só porque leu que "é o certo"; o certo é o que o seu risco pede.

Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Por que o servidor precisa validar o input

O coração do modelo servidor-autoritativo é uma frase: nunca confie no cliente. O cliente manda intenção, o servidor valida e aplica. A palavra que faz todo o trabalho ali é "valida".

Imagine um cliente pedindo para se mover. A versão ingênua manda a posição final direto:

# RUIM: cliente manda a posicao pronta, servidor obedece
@rpc("any_peer", "unreliable")
func mover_para(nova_pos: Vector2) -> void:
    position = nova_pos  # confiou cegamente, deu teleporte/wallhack

Qualquer cliente modificado manda mover_para(Vector2(99999, 0)) e atravessa o mapa. O servidor engoliu. A versão correta recebe só a direção (a intenção) e o próprio servidor calcula o movimento, respeitando a velocidade máxima e as colisões que ele conhece:

# BOM: cliente manda intencao, servidor calcula e valida
@rpc("any_peer", "unreliable")
func pedir_movimento(direcao: Vector2, delta: float) -> void:
    if not multiplayer.is_server():
        return
    # o servidor so aceita um vetor normalizado e aplica a SUA velocidade
    var passo: Vector2 = direcao.normalized() * VELOCIDADE_MAX * delta
    velocity = passo / delta
    move_and_slide()

O servidor normaliza a direção (então mandar um vetor gigante não adianta), aplica a velocidade que ele define, e roda a colisão na própria simulação. O cliente não consegue impor uma posição; ele só sugere para onde quer ir.

O mesmo raciocínio vale para tudo que dá vantagem. Tiro? O cliente avisa que atirou, o servidor checa cooldown, munição e se o alvo está mesmo na mira antes de aplicar dano. Compra na loja? O servidor confere se o jogador tem o ouro, não o cliente. A pergunta que você faz em cada ação é: "se o cliente mentir neste número, ele ganha vantagem?". Se a resposta é sim, a decisão é do servidor.

Validação de input é uma das camadas de proteção, não a única. Para ver o quadro completo de como blindar um jogo competitivo, vale ler sobre anti-cheat em jogos online indie, que trata das outras frentes além da autoridade de rede.

O padrão: cada cliente é dono só do próprio input

Juntando tudo, surge o desenho que a maioria dos jogos sérios usa. Ele parece contraditório à primeira vista, mas é elegante: cada cliente tem autoridade sobre o próprio input, e o servidor tem autoridade sobre o estado resultante.

Na prática, isso significa separar duas coisas que iniciantes costumam misturar:

  • Input (o que o jogador quer): direção do movimento, botão de atirar, comando de pular. Isso o cliente lê localmente e manda para o servidor. É barato e dá a sensação de resposta imediata.
  • Estado (o que de fato aconteceu): posição real, vida, munição, placar. Isso só o servidor decide, e os clientes recebem via sincronizador.

No Godot, um jeito de montar isso é dar ao cliente autoridade sobre um node de input (ou um MultiplayerSynchronizer configurado para enviar só as teclas, do cliente para o servidor), enquanto o node do personagem em si fica com autoridade do servidor:

extends Node
# node de input, autoridade do cliente dono do personagem

var direcao: Vector2 = Vector2.ZERO
var atirando: bool = false

func _process(_delta: float) -> void:
    if not is_multiplayer_authority():
        return
    # so o dono le o teclado e preenche a intencao
    direcao = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    atirando = Input.is_action_pressed("atirar")

O servidor, dono do personagem, lê esse input já sincronizado e aplica a lógica no _physics_process, validando tudo. Repare na inversão de fluxo em relação ao sincronizador de posição: o input flui do cliente para o servidor, enquanto a posição flui do servidor para os clientes. São dois MultiplayerSynchronizer com donos diferentes, e entender essa separação é o pulo do gato.

O benefício é duplo. O jogador sente controle imediato, porque o input dele é local. E o jogo continua honesto, porque nenhum cliente consegue impor posição, vida ou dano: ele só preenche uma caixinha de intenção que o servidor é livre para ignorar se não fizer sentido. Um cheater que mande "atirando = true" o tempo todo esbarra no cooldown que o servidor controla.

Se você quiser esconder a latência e fazer o personagem reagir no mesmo frame em que a tecla é apertada, o próximo passo é a predição de cliente com reconciliação, em que o cliente simula o movimento localmente e corrige quando o servidor discorda. Isso é um tema por si só, e dá para viver bem sem ele num jogo de ritmo mais calmo. Comece pelo servidor-autoritativo puro, meça se a latência incomoda, e só então adicione predição.

Fechando

A autoridade de servidor no Godot multiplayer cabe em poucas ideias que se reforçam. Todo node tem uma autoridade (por padrão o servidor, id 1), que você consulta com get_multiplayer_authority() e is_multiplayer_authority() e define com set_multiplayer_authority(), de forma determinística em todas as máquinas. A autoridade é por node, então você mistura e combina: o personagem de cada jogador pode ser dele, enquanto inimigos e placar ficam com o servidor.

A decisão que importa é entre cliente-autoritativo (simples, mas confia no cliente) e servidor-autoritativo (a fonte da verdade é o servidor, que valida tudo). Em qualquer jogo com incentivo para trapaça, a regra é não confiar no cliente: ele manda a intenção de input, e o servidor valida antes de aplicar. O padrão que amarra isso é dar a cada cliente autoridade apenas sobre o próprio input, deixando o estado resultante sempre nas mãos do servidor.

Para seguir daqui, revise o multiplayer no Godot com RPC com esses olhos novos (vai reparar que os modos authority e any_peer do @rpc são exatamente sobre autoridade), fuce o resto do ecossistema da engine no hub do Godot, e quando o jogo já aguentar jogadores curiosos, aprofunde as defesas com anti-cheat em jogos online indie. Autoridade bem desenhada é a fundação; o resto é construir em cima dela sem nunca deixar o cliente mandar no que não deve.

Perguntas frequentes

O que é autoridade de servidor no Godot multiplayer?

É o peer que tem o direito de decidir o estado de um node. No Godot 4 cada node tem uma autoridade de rede, consultada com get_multiplayer_authority() e definida com set_multiplayer_authority(id). No modelo servidor-autoritativo, o servidor (id 1) é a fonte da verdade: ele valida o input dos clientes e aplica o resultado. Os outros pares só recebem e exibem.

Como definir a autoridade de um node?

Com node.set_multiplayer_authority(id), passando o id do peer que deve mandar naquele node. Por padrão todo node tem autoridade 1 (o servidor). Você chama isso nos dois lados da conexão, de forma determinística, para que todas as máquinas concordem sobre quem é o dono. Dentro do código, is_multiplayer_authority() retorna true só na máquina que tem a autoridade.

Qual a diferença entre servidor-autoritativo e cliente-autoritativo?

No cliente-autoritativo, cada cliente decide seu próprio estado (posição, vida) e os outros confiam nele. É simples, mas abre a porta para trapaça, porque um cliente modificado pode mentir. No servidor-autoritativo, o servidor valida tudo e só ele muda o estado oficial; o cliente só manda intenção de input. É mais trabalhoso e tem mais latência, mas é o único modelo seguro contra trapaça.

Por que o servidor deve validar o input do cliente?

Porque o cliente roda na máquina do jogador e pode ser modificado. Se o servidor aceitar cegamente "andei 500px" ou "causei 9999 de dano", um cheater explora isso. A regra é não confiar no cliente: ele manda a intenção (direção, "atirei") e o servidor checa se faz sentido (velocidade, munição, cooldown, linha de visão) antes de aplicar.

Cada jogador tem autoridade sobre o quê?

No padrão recomendado, cada cliente tem autoridade apenas sobre o próprio input, não sobre o resultado. Ou seja, o cliente é dono de dizer para onde quer andar e quando quer atirar, mas o servidor continua dono da posição real, da vida e do placar. Isso dá resposta imediata ao jogador sem entregar o estado do jogo para quem pode mentir.

Preciso de servidor-autoritativo num jogo coop entre amigos?

Nem sempre. Se é um coop PvE entre amigos que confiam uns nos outros, o custo de validar tudo no servidor pode não valer a pena, e um modelo mais frouxo resolve. O servidor-autoritativo é obrigatório quando existe competição e incentivo para trapacear, como PvP ranqueado. Escolha o modelo pelo risco real do seu jogo, não por dogma.