Esta página ainda não foi traduzida: mostrando a versão em inglês.
Inventory
Um único conjunto de linhas com dono, usado por tiros, drops, habilidades e movimentação. As pilhas mudam por incremento, e o teto por dono se comporta no limite como você escolher.
Quando usar
- Os jogadores possuem coisas, e cada posse é uma linha com dono: lida por dono, com teto por dono e com o comportamento de excedente declarado, não herdado de um padrão.
- Uma quantidade se acumula: uma pilha (stack) muda por incremento com chave de idempotência, então um débito repetido não debita duas vezes.
- Outros módulos gastam do mesmo conjunto: tiros debitam munição, drops concedem loot, compras aparecem como linhas vinculadas ao direito de uso (entitlement) correspondente.
- Dispensável quando o número não é algo que se possua. HP, XP e cooldowns ficam nos stats.
Quem faz o quê
| Ator | O que faz nesta página |
|---|---|
player | lê as próprias posses e gasta delas |
backend-service | concede, incrementa e revoga em nome de um jogador, informando para quem está agindo |
Resumo
fn: conceder munição, mover um item para o slot de equipamento primary, verificar se o saldo basta antes de gastar// fn authority — a cloud function, or a dedicated server holding a host key
var bag = await player.Inventory.Container("bag");
var equipment = await player.Inventory.Container("equipment");
await player.Inventory.Grant("ammo.shell", count: 20);
await bag.Move(itemId, to: equipment, slot: "primary");
if (await player.Inventory.CanAfford("ammo.shell", 1))
await player.Inventory.Consume("ammo.shell", 1);// fn authority — a cloud function, or a dedicated server holding a host key
const bag = await player.inventory.container('bag');
const equipment = await player.inventory.container('equipment');
await player.inventory.grant('ammo.shell', { count: 20 });
await bag.move(itemId, { to: equipment, slot: 'primary' });
if (await player.inventory.canAfford('ammo.shell', 1))
await player.inventory.consume('ammo.shell', 1);# fn authority — a cloud function, or a dedicated server holding a host key
bag = await player.inventory.container("bag")
equipment = await player.inventory.container("equipment")
await player.inventory.grant("ammo.shell", count=20)
await bag.move(item_id, to=equipment, slot="primary")
if await player.inventory.can_afford("ammo.shell", 1):
await player.inventory.consume("ammo.shell", 1)Ainda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.
// fn authority — a cloud function, or a dedicated server holding a host key
Client->Commerce->Entitlements->Grant(FPSIdempotencyKey(GrantId), PlayerId, PSKeys::Item::AmmoShell);
// spending is an instance act on the entitlement you hold
Entitlement->Spend(FPSIdempotencyKey(SpendId), /*Amount*/ 1,
TPSOnResult<void>::CreateLambda([](const TPSResult<void>& Result)
{
// short on the item is a declared refusal, not a silent no-op
if (Result.IsRefused()) { DeclineReload(Result.Refusal()); }
}));
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.// fn authority — a cloud function, or a dedicated server holding a host key
var bag = await player.Inventory.Container("bag");
var equipment = await player.Inventory.Container("equipment");
await player.Inventory.Grant("ammo.shell", count: 20);
await bag.Move(itemId, to: equipment, slot: "primary");
if (await player.Inventory.CanAfford("ammo.shell", 1))
await player.Inventory.Consume("ammo.shell", 1);A sessão de um jogador faz as leituras, as movimentações e a verificação de saldo com as mesmas chamadas. Conceder, consumir e destruir não cabem a ela: a plataforma recusa essas operações como proibidas e informa qual direito falta a quem chamou, seja qual for o binding que fez a chamada.
O modelo
Um inventário não traz nenhuma noção própria. É um preset: uma forma montada com o que a entidade já oferece, então tudo abaixo é declaração de entidade, não um mecanismo desta página.
| Declara | O que é |
|---|---|
| um tipo com dono | a posse pertence a um dono, e a seleção por dono é uma operação da própria entidade |
uma ref para um item do catálogo | a referência guarda o id do item, nunca a key, então renomear uma chave é seguro. A definição do item fica no comércio |
| um aspecto de pilha com incremento | a pilha muda por um delta, não sobrescrevendo o que foi lido (veja abaixo) |
| um teto por dono com o comportamento no limite | uma de três opções, e não existe padrão: refuse · redirect para um compartimento de dono declarado · discard with event |
Passe uma chave de idempotência em todo incremento
Um incremento não é idempotente: dois incrementos são dois incrementos. Ele precisa levar uma chave de idempotência, senão um débito repetido debita duas vezes; para saber o resultado, faça uma leitura endereçada.
O que vale para toda posse.
| Sempre | O que é |
|---|---|
o teto não tem padrão | as três respostas para uma mochila cheia são três jogos diferentes: a recusa faz o jogador perder o loot bem na frente dele, o redirecionamento é um correio ou um depósito que transborda, e o descarte é uma perda silenciosa, legítima só porque foi declarada e pode ser observada. Nenhum padrão serve para os três, então quem escolhe é a declaração |
o dono é imutável | nada muda de mãos editando um campo: uma posse se move como uma revogação mais uma nova concessão com origem declarada, e os dois fatos ficam registrados |
uma transferência entre dois jogadores | é outra promessa: exige custódia (escrow) e antifraude, e fica fora desta versão |
uma linha | exibe um direito de uso, em vez de ser uma segunda fonte dele: o que foi comprado fica no comércio, e a linha aqui o representa |
Erros
- A instância não existe, ou um predicado a esconde: a resposta é not found nos dois casos, então uma recusa nunca revela que algo existe mas não é seu.
- Um campo não declarado no aspecto (incluindo os aninhados) e um campo obrigatório sem valor são recusas de validação que indicam o campo.
- A versão não bateu é uma falha de pré-condição, e vale repetir depois de ler de novo.
- Uma escrita em nome de um jogador que não informa o jogador é uma recusa de validação, não uma escrita silenciosa como se fosse outra pessoa.
- Falta de permissão para ler ou escrever responde forbidden, com leitura e escrita diferenciadas.
Limites
Os números chegam com o capítulo de limites da plataforma; o que acontece em cada teto já está definido.
- Instâncias por dono: pela regra declarada acima, e não existe padrão.
- Tamanho da instância armazenada: a escrita é recusada como conflito, e a recusa indica o campo responsável e o tamanho medido. O teto é atingido por acúmulo, então dá para observar a aproximação antes da escrita que falha.
- Frequência de mudanças numa instância: recusa por limite de frequência, com prazo para tentar de novo.
- Tamanho da página de seleção: a página é cortada no teto e a flag “há mais” continua verdadeira; devolver menos sem a flag é proibido.