Esta página ainda não foi traduzida: mostrando a versão em inglês.
PlayServ SDK
O backend de jogo que já vem com o gameplay. PlayServ é um backend-as-a-service para jogos live: o estúdio roda o backend do jogo — dados, jogadores, salas, matchmaking, comércio — sem hospedar nenhum servidor. O SDK é a forma como o seu código, no servidor e na engine, trabalha com essa plataforma.
A simulação não é o seu código
Salas, colisões, movimentação, predição e sincronização rodam todas dentro da plataforma. O seu jogo se resume a declarações (entidades, mapas, habilidades, tabelas de drops, política de sincronização), hooks (as suas regras, chamadas em etapas com nome), eventos (você assina em vez de consultar em loop) e operações (o que você pede ou comanda). Toda página de módulo se organiza exatamente em torno dessas quatro formas.
O que você deixa de escrever é bem concreto: loop de jogo, montagem de snapshots, codificador de deltas, resolução de colisões, integração de movimento, tratamento de reconexão, validação de acertos com compensação de lag. Um jogo como o Tanks cabe em ~300 linhas. Primeiros passos mostra como montá-lo.
Alterar o estado declarado já é a chamada de rede
Não existe chamada de envio. Você declara como um campo se sincroniza com um único atributo ao lado dele, e alterar o campo já é a operação de rede. Deltas em relação ao último estado confirmado, política por aspecto, prioridade e taxa de envio, a janela de retenção e os hooks de mudança decorrem dessa declaração; você não escreve nada disso.
O mesmo vale para tudo o que é declarado: um evento, um RPC, um grupo, um eixo de ranking. Uma única declaração vira a API tipada em todos os bindings, uma tela no painel de administração, etapas com nome que os seus hooks podem substituir, regras de acesso por ator e código gerado para cada binding. É por isso que você versiona a declaração, e não o código gerado. Veja Data & Subscriptions e Esquema como código.
A interface segue o ator, não o lado
Não existe SDK de cliente nem SDK de servidor. É um SDK só, e o que uma chamada pode fazer é decidido pelo ator por trás dela — um jogador, um serviço, o cérebro de um bot, um operador.
O caso para o qual ele foi pensado é a máquina de um jogador que cria uma sala (room) e depois a executa: um cliente mestre, com as interfaces de dono da sala e nada além disso. Um build room-visitor não tem expulsar nem fechar: essas interfaces não existem nele, não estão apenas desativadas.
Os direitos são compostos a partir de permissões atômicas, então não há níveis de papel prontos, e um papel (role) controla o acesso aos dados até a linha e a coluna. Veja Quem toma as decisões e, para saber como se escrevem as permissões concedidas (grant), Access & Roles.
Um design, uma pilha
Como é escrito
O SDK é um design só, com duas maneiras de especializá-lo, e nada desce de nível enquanto o nível de cima conseguir expressá-lo. Os princípios comuns são idênticos em todos os bindings. A forma de uma linguagem fica só com o que o paradigma dela não consegue expressar do jeito comum. A forma de uma engine fica só com o que a engine remodela em cima da linguagem — no Unreal, uma declaração vai dentro da própria macro de reflexão da engine.
Como roda
O código do seu jogo lida com módulos e nada mais. Os módulos são montados a partir de quatro primitivas — eventos, RPC, dados e assinaturas, grupos. Abaixo delas fica o hub, que você nunca chama: injeção de dependências, montagem de módulos, a sessão, recuperação de estado, qualidade de serviço das mensagens. Mais abaixo ainda, os adaptadores de transporte, um por protocolo — e qual deles carrega uma chamada o seu código não decide nem percebe.
As duas metades em detalhe: Como o SDK é construído, terminando em Por baixo dos panos.
Módulos se compõem; nada é subclasse
Não existe módulo base do qual derivar nem hierarquia para estender — os módulos formam um grafo, porque as funcionalidades reais cruzam ramos: o matchmaking reserva vagas (seat) em salas, os drops posicionam itens pelo mapa, um chat vive dentro de uma sala.
“Herança” cobre aqui quatro mecanismos diferentes, e vale a pena distingui-los: os RPCs de uma entidade fazem parte da entidade; um preset é um pacote nomeado de aspectos, não uma classe base; sobrescrever uma etapa da plataforma é pôr um atributo na sua substituta; um módulo usa outro por meio de um decorator que restringe a interface emprestada. Veja Herança e composição.
Quem vê o quê é declarado, não filtrado no cliente
Com quarenta jogadores, um snapshot da sala inteira resolve; com duzentos, não. As regras de área de interesse (interest rules) decidem quem recebe qual fatia, e pacotes por ator e difusão (broadcast) são dois modos de entrega de um mesmo modelo declarado — passar de um para o outro é configuração, não reescrita. O que está longe perde qualidade pelos níveis de detalhe declarados antes de sumir.
Isso também é uma propriedade de segurança: o estado que não pode vazar nunca é enviado. A névoa de guerra e os campos visíveis só para o dono não estão no pacote, em vez de estarem escondidos no cliente. Espectadores, admins e replays ganham uma visão mais ampla por terem permissões concedidas mais amplas. Veja Visibility.
O que sobrevive à perda de um host
A queda de um host não encerra a partida. O estado da sala não é copiado entre hosts durante o jogo: um único dono mantém a ordem das operações sem precisar de consenso. A partida sobrevive porque o estado dela é declarado, e o estado declarado fica guardado fora do host, em snapshots feitos num intervalo declarado. Um host substituto retoma a partir do último snapshot.
O substituto tem o estado inteiro como estava naquele snapshot, então o que foi jogado desde então se perde. Um deploy usa o mesmo mecanismo sem essa perda: retirar um host de serviço (drain) é o caminho do failover executado de propósito.
O estado que só existe na engine não é recuperado
O estado que você guarda apenas em atores da engine não é declarado, então o host substituto não o tem. ::: Veja O que sobrevive à perda de um host e, para o período de tolerância (grace window) em que um jogador pode voltar, Rooms.
Qualquer etapa da plataforma pode ser sua
Todo cenário da plataforma é uma cadeia de funções registradas, e você substitui ou envolve um elo. Login, validação de entrada, compra, envio, upload — cada um é uma etapa com nome. A sua substituta é declarada com um atributo, as versões são escolhidas por condição e a etapa da própria plataforma fica como fallback.
Em vez de fazer um fork do código da plataforma, você substitui as etapas dela. Veja Extensibility.
Uma interface, seis linguagens
Um contrato, seis projeções: C#, TypeScript, Python e Go no servidor; Unreal C++ e Unity C# gerados na engine. Todo exemplo de código deste site mostra as seis, e quando um binding não tem interface para uma etapa, a aba explica o motivo: a etapa roda fora da engine, ou outro ator é quem tem o direito de fazer aquela chamada.
Duas consequências que vale conhecer antes de escolher uma linguagem. O RPC recebe objetos do SDK por referência, e não DTOs achatados. E as primitivas assíncronas já vêm prontas — canais, fluxos (stream) e endereçamento de grupo: dá para falar com um grupo inteiro e coletar as respostas, ou consumir um arquivo em pedaços enquanto ele ainda está sendo enviado.
Existe também um host determinístico em memória, que roda o código do seu jogo sem nenhum backend por trás e com o tempo sob o seu controle, então os testes são determinísticos. Veja Threads, ciclo de vida e testes.
O que fica fora do SDK de propósito — deploys, cobrança, administração da organização e dos usuários — está no plano do operador. A barra lateral é o mapa de todo o resto; Primeiros passos é o caminho mais curto para começar.