Neste post
  1. O que "no servidor" significa aqui
  2. Isso é mais chato de construir
  3. O motivo não é só trapaça
  4. O caso que torna isso inegociável: mais de um país
  5. Trocar um subsistema com o jogo no ar
  6. O terceiro motivo, que quase ninguém cita
  7. Quando isso é excesso
  8. O resto da stack
  9. Resumo

O CyberDropX começou como um minijogo e virou dezoito — plinko, mines, hi-lo, tower, quebra-código, raspadinha, reflexo e outros, todos com partidas de menos de um minuto. Por cima disso existem missões, esquadrões, indicação, ranking global e saque.

A parte que deu mais trabalho não foram os jogos. Foi mover toda a economia para o servidor.

O que "no servidor" significa aqui

Cada recompensa é decidida numa Cloud Function. O cliente não calcula ganho, não valida partida e não informa resultado — ele informa intenção, e o servidor responde com o desfecho.

A distinção entre informar resultado e informar intenção é a coisa mais importante deste post:

O cliente enviaConsequência
"ganhei 300 moedas"não existe validação que conserte isso
"iniciei a partida X" / "escolhi a casa 3"o servidor decide, e a decisão é a verdade

Se o cliente manda o resultado, qualquer verificação posterior é heurística. Se ele manda a jogada, não há o que verificar — ele nunca teve a informação para mentir.

Validar o que o cliente reportou é jogo perdido. O único desenho que funciona é o cliente não ter a informação que ele poderia falsificar.

Isso é mais chato de construir

Vale ser específico sobre o custo, porque ele é real:

  • Cada ação com valor vira ida e volta pela rede.
  • O estado precisa ser reconciliado quando a resposta demora ou se perde.
  • Não existe modo offline para nada que envolva economia.
  • Erro de rede no meio de uma partida precisa de tratamento — e "tentar de novo"

não pode dar prêmio duas vezes.

Esse último item merece nota: toda operação de valor precisa ser idempotente. Se o jogador toca duas vezes, se a rede reenvia, se o app reinicia no meio, o resultado tem que ser o mesmo. Sem isso, o próprio jogador honesto vira fonte de inconsistência.

O que ameniza a lentidão é dividir com clareza:

partida            -> roda local, com resposta imediata
resultado da rodada-> decidido no servidor
saldo e ranking    -> so o que o servidor disser

A animação, o som e a sensação de resposta acontecem no aparelho. O número que importa vem de fora.

O motivo não é só trapaça

A resposta óbvia para "por que no servidor" é para ninguém trapacear, e ela está certa — mas é a menos interessante.

O motivo real é este:

Uma economia no cliente é uma economia que você não pode mudar.

Se o balanceamento vive dentro do aplicativo, corrigir um número exige nova versão, revisão da loja e esperar todo mundo atualizar. Na prática, isso significa:

  • uma correção urgente leva dias, não minutos
  • durante esse tempo o jogo continua desbalanceado
  • e mesmo depois, quem não atualizou continua na versão antiga — com uma economia

diferente da dos outros, no mesmo ranking

Com a lógica no servidor, um ajuste de balanceamento é um deploy.

Num jogo com dezoito modos e ranking global, você vai errar o balanceamento. A única pergunta é quanto tempo leva para consertar.

O caso que torna isso inegociável: mais de um país

O CyberDropX é multi-país e tem interface em dez idiomas. Isso parece assunto de tradução e não é: é assunto de economia.

Recompensa que termina em saque tem valor em dinheiro, e dinheiro não é igual em todo lugar. Muda a moeda, muda quanto vale um anúncio assistido naquele mercado, mudam as regras de pagamento e os limites de cada meio de saque. Nada disso é estável — o valor de um anúncio oscila sozinho, sem ninguém mexer em nada.

Com a economia dentro do aplicativo, cada um desses ajustes vira uma versão nova na loja. Some as duas lojas, o tempo de revisão e o fato de que parte da base nunca atualiza, e o resultado é um jogo onde o mesmo anúncio paga valores diferentes dependendo da versão instalada — no mesmo ranking global.

Onde vive a tabela de valoresAjustar um país custa
No aplicativoduas revisões de loja e uma base fragmentada
No servidorum deploy

Trocar um subsistema com o jogo no ar

Tem uma pista disso no próprio produto: o sistema de missões está na segunda versão. Substituir a mecânica de missões inteira, com gente jogando, só é uma tarefa razoável porque as missões não moram no aplicativo instalado. Se morassem, "missões v2" seria uma migração de dados no aparelho de cada jogador, com duas versões coexistindo por meses.

Vale registrar também o estágio: o CyberDropX ainda está em 0.3.0. Nada aqui é relato de produto maduro com milhões de usuários — é o desenho escolhido antes de a base existir, que é exatamente quando essa escolha é barata.

O terceiro motivo, que quase ninguém cita

Há um benefício que aparece depois e é grande: observabilidade.

Quando toda decisão de valor passa pelo servidor, você tem o registro de todas elas. Isso permite responder perguntas que, do lado do cliente, seriam impossíveis:

  • qual dos dezoito modos as pessoas realmente jogam
  • em que ponto da sessão elas param
  • qual recompensa está gerando mais retorno no dia seguinte
  • se existe um padrão anômalo concentrado em poucas contas

Nenhuma dessas respostas exige rastrear o usuário além do necessário — são eventos da própria economia, que já precisavam existir para o jogo funcionar.

E há um efeito colateral prático: quando alguém reclama que o saldo está errado, existe um histórico para conferir. Sem isso, a conversa é a palavra do jogador contra um número.

Quando isso é excesso

Nem todo jogo precisa disso, e recomendar o contrário seria desonesto.

A pergunta que decide:

Existe algo com valor real do lado de fora — saque, prêmio, ranking que dá algo, item comprado com dinheiro?

Se não existe, economia no servidor é complexidade sem retorno. Um jogo idle puramente local, como o descrito em Lógica em Dart puro, não ganha nada com isso — o único prejudicado por uma trapaça é quem trapaceia.

Se existe, não é opcional. E vale notar que o gatilho aparece tarde: muitos jogos começam sem valor externo e ganham depois. Migrar economia de cliente para servidor com base instalada é uma das piores tarefas que existem, porque envolve decidir o que fazer com saldos que podem ter sido obtidos de forma inválida.

O resto da stack

Flutter e Firebase, dez idiomas, Android e iOS. O ranking é global de propósito — competição entre países se mostrou mais interessante que competição local numa base ainda pequena, porque ranking local com poucos jogadores é ranking vazio.

Uma consequência disso que só se percebe depois: ranking global também só funciona com economia no servidor. Colocar jogadores de países diferentes na mesma tabela exige que todos tenham jogado sob a mesma regra, e a única forma de garantir isso é a regra não estar no aparelho de ninguém.

Resumo

  • O cliente envia intenção, não resultado. Validar resultado reportado é jogo

perdido.

  • Toda operação de valor precisa ser idempotente, ou o jogador honesto vira fonte

de erro.

  • Partida roda local; o número vem do servidor. É o que salva a sensação de

resposta.

  • O motivo principal não é trapaça: é poder corrigir balanceamento sem publicar

versão.

  • Observabilidade e histórico de disputa são benefícios que só aparecem depois.
  • Se não há valor real do lado de fora, isso é excesso. Se há, não é opcional —

e migrar depois é caro.

Perguntas frequentes

Isso não deixa o jogo mais lento?

Deixa, e é o custo real. Cada ação com valor vira ida e volta. O que ameniza é separar o que precisa de servidor do que não precisa: a partida roda local, só o resultado é decidido do outro lado.

Dá para jogar offline?

Não para nada que envolva economia. Um minijogo pode até rodar sem rede, mas o prêmio só existe quando o servidor concordar. Fingir que a recompensa foi dada e reconciliar depois cria o pior dos mundos: o jogador vê um número que pode sumir.

Como evitar que o cliente 'informe' o resultado?

Não pedindo o resultado a ele. O cliente envia a intenção — 'iniciei esta partida', 'escolhi esta casa' — e o servidor decide o desfecho. Se o cliente manda 'ganhei 300', não existe validação possível que conserte isso.

Vale essa complexidade num jogo pequeno?

Depende de uma pergunta só: existe algo com valor real do lado de fora — saque, prêmio, ranking que dá algo? Se não existe, é excesso. Se existe, não é opcional.