Esta página ainda não foi traduzida: mostrando a versão em inglês.
Visibility
Com 40 jogadores, um snapshot da sala inteira funciona. Com 200, não. Uma zona de visibilidade decide quem recebe o quê, como um predicado declarado, e não como uma chave que você liga objeto por objeto. A difusão e os pacotes por ator são dois modos de entrega declarados do mesmo modelo, então trocar um pelo outro é questão de configuração, e não de reescrever código. É uma otimização do canal, e não uma permissão — para isso, veja Access & Roles.
O mesmo modelo declarado (o predicado, as camadas, os níveis de detalhe) é lido de duas formas:
| Difusão | Pacotes por ator | |
|---|---|---|
| Envia | a sala (room) inteira, para todos | a cada jogador, só a parte que as regras dele selecionam |
| Serve para | uma sala pequena; é o padrão | uma multidão, em que o tamanho do pacote precisa continuar previsível |
| Lê a declaração | uma vez, para a sala | por ator |
O que não pode vazar não está no pacote, em vez de ficar oculto no cliente: nunca é enviado, e por isso é uma propriedade de segurança, e não de banda.
Quando usar
- Suas salas ficaram grandes demais para a difusão (broadcast) da sala inteira: 200 jogadores precisam de fluxos da vizinhança por cliente, e não de todos os deltas.
- O estado não pode vazar: névoa de guerra e campos visíveis só para o dono nunca devem ser enviados, em vez de ficarem ocultos no cliente.
- Várias sessões compartilham um mapa e não podem se ver: uma camada é só mais um predicado.
- O tamanho do pacote precisa ser previsível numa multidão: limite os objetos e declare a ordem, para que “os N mais próximos” seja uma promessa, e não um acaso da densidade.
- Um jogador na fronteira precisa enxergar o outro lado: declare quais áreas vizinhas são visíveis, porque, por padrão, só a dele é.
- Dispensável quando a sala é pequena. O modo de entrega (delivery mode) com pacote compartilhado já cobre esse caso.
Quem faz o quê
| Ator | O que faz nesta página |
|---|---|
schema-author | declara o predicado de visibilidade, o limite de objetos e sua ordem, quais áreas vizinhas são visíveis e o modo de entrega |
any | assina e recebe o que a zona admite; pode baixar o limite de objetos para si mesmo, dentro dos limites declarados |
Resumo
Tank; Ammo com escopo do dono, ao lado do campo[Entity("tank")]
[Visible(Radius = 60)] // spatial
[Visible(Rule.SameLayer)] // layers of one map
public class Tank
{
[Sync] public Vector3 Position;
[Sync(To = Scope.Owner)] public int Ammo; // per-field scope
}@Entity('tank')
@Visible({ radius: 60 }) // spatial
@Visible(Rule.SameLayer) // layers of one map
export class Tank {
@Sync() position!: Vector3;
@Sync({ to: Scope.Owner }) ammo = 0; // per-field scope
}@entity("tank")
@visible(radius=60) # spatial
@visible(Rule.SAME_LAYER) # layers of one map
class Tank:
position: Vector3 = sync()
ammo: int = sync(to=Scope.OWNER) # per-field scopeAinda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.
// multi-entry values are one quoted list (a specifier value is a single token)
UCLASS(PSEntity = "tank",
PSVisible = "radius:60, rule:SameMapInstance") // spatial + instances of one map
class UTank : public UObject
{
GENERATED_BODY()
UPROPERTY(PSSync) FVector3f Position;
UPROPERTY(PSSync = (To = "Owner")) int32 Ammo; // per-field scope
};
// declarations compile into the same pushed model — playserv push from the UE project or CI[Entity("tank")]
[Visible(Radius = 60)] // spatial
[Visible(Rule.SameLayer)] // layers of one map
public class Tank
{
[Sync] public Vector3 Position;
[Sync(To = Scope.Owner)] public int Ammo; // per-field scope
}O modelo
O que uma regra de visibilidade declara.
| Declara | O que é |
|---|---|
predicado | a própria regra, escrita na mesma linguagem de predicados dos predicados de acesso e das condições de transição. Raio, instância de mapa, equipe e dono são casos particulares de um predicado, e não mecanismos à parte — o contrato tem exatamente uma linguagem desse tipo |
limite de objetos e sua ordem | uma regra pode limitar o número de objetos, e aí a ordem de seleção é declarada, e não deduzida: “os N mais próximos” é um predicado, mais uma ordenação por distância, mais um limite. Um predicado sozinho não consegue expressar isso, porque responde “esta linha se qualifica?”, e não “qual das qualificadas está mais perto?” |
áreas vizinhas | se os objetos de uma sala ou instância de mapa vizinha são visíveis, e quais exatamente. Nunca implícito: sem declaração, a área é aquela em que o destinatário está |
modo de entrega | pacote compartilhado: o mesmo conteúdo para todos, barato em CPU. pacote por ator: cada destinatário recebe o seu, conforme a zona dele; caro em CPU e indispensável com populações grandes |
O que vale para toda zona.
| Sempre | O que é |
|---|---|
visibilidade | não é uma permissão: o que a zona esconde pode estar disponível por permissão, e vice-versa (veja abaixo) |
o destinatário | pode baixar o limite: dentro do máximo declarado e nunca abaixo do mínimo declarado, porque o predicado é o mesmo para todos cujo contexto coincidiu, enquanto o tamanho do pacote é problema do destinatário |
truncamento | é observável: o destinatário fica sabendo que o pacote foi cortado e por qual ordem. O truncamento silencioso é proibido, porque não dá para distingui-lo da falta de outros objetos |
degradação | é declarada: quando acaba o orçamento para montar pacotes por ator, a plataforma volta ao pacote compartilhado como foi declarado, em vez de começar a perder destinatários de forma arbitrária |
formato do pacote | é uma promessa fraca: o tamanho e a composição de um pacote não deveriam permitir deduzir que existem objetos ocultos |
Visibilidade não é permissão
A zona é uma otimização do canal, e não controle de acesso. Não misture os dois: uma configuração de névoa de guerra ampliaria direitos sem ninguém perceber, ou os direitos passariam a depender da distância. O tamanho do pacote pode dar pistas de que existem objetos ocultos; então, quando a existência deles não pode vazar, use as permissões de Access & Roles, e não a zona.
Tanto “quem vê isto?” quanto “o que essa pessoa vê?” podem ser consultados. O custo dos pacotes por ator é uma leitura de primeira classe, no código e no painel.
Erros
- Um alvo de assinatura (subscription) não declarado é uma recusa de validação.
- Sem permissão para assinar, a resposta é forbidden ou not found, conforme a existência do alvo seja ou não um segredo: a própria recusa não pode revelar o que está recusando.
- Uma posição de retomada que não pode ser interpretada é uma requisição inválida, e não um reinício silencioso a partir de agora.
- Uma assinatura que a plataforma encerrou e um número de assinaturas esgotado são, ambos, conflitos.
- Ampliar uma visão é
fn. Conceder uma visão ampliada e definir níveis de detalhe (detail tier) são recusados com forbidden para uma sessão de jogador, e a visão dela não muda: um cliente espectador não consegue ampliar as próprias permissões concedidas. - Uma instância que a visão de quem chama exclui responde
not found, a mesma resposta de uma instância inexistente — um forbidden confirmaria que existe algo atrás do muro. - Ler o custo dos pacotes por ator é
fnadm: uma cloud function ou o painel, nunca um cliente.
Limites
Os números chegam com o capítulo de limites da plataforma; o que acontece em cada teto já está definido.
- Custo de um pacote por ator: quando o orçamento acaba, a degradação declarada para o pacote compartilhado, com aviso, e nunca a perda arbitrária de destinatários.
- Objetos por regra: limitados, com uma ordem declarada e uma flag de truncamento observável.
- Assinaturas por ator: uma nova é recusada, e as existentes continuam.
- Tamanho do delta: o delta é dividido, e não truncado, e a divisão é observável.
- Taxa de envio: um limite superior, e não uma garantia.