Pular para o conteúdo

Fluxos in-game

Esta página junta tudo: pega cada gesto que o jogador faz no jogo e o segue até a plataforma e de volta. São cinco fluxos, e todos compartilham o mesmo esqueleto — o client pede pelo opcode 221, o servidor valida e delega ao Agent, a plataforma responde, o servidor devolve pelo opcode 220. O que muda é o que cada um pede e o que a UI faz com a resposta.

Vale reler antes a arquitetura, porque os opcodes e o papel do Agent aparecem em todos os fluxos abaixo.

Antes de anunciar ou comprar, o personagem precisa estar vinculado a uma conta Lootfy. O módulo detecta a falta de vínculo pela elegibilidade e encurta a jornada abrindo o navegador sozinho.

  1. O gatilho. A elegibilidade volta com blocker == 'NOT_LINKED'. A UI mostra o botão “Vincular personagem” e, se alguma janela Lootfy está visível, dispara o auto-vínculo — uma vez por sessão, para o navegador não abrir com nada na tela.

  2. O pedido. A função requestLink() manda link@{} no opcode 221. Os botões “Vincular personagem” fazem o mesmo, manualmente e sem trava de uma-vez-por-sessão.

  3. O servidor. O opcode.lua inicia o vínculo (vincular personagem, POST /v1/api/character-links) sempre sobre o personagem do cid da sessão — ignora qualquer ref no payload. O Agent chama a plataforma, que devolve um link de uso único.

  4. A volta. O servidor manda link@<url> no opcode 220. O módulo abre a URL no navegador do jogador, onde ele confirma o vínculo logado na conta Lootfy.

A elegibilidade é a pré-checagem que destrava (ou tranca) as ações Lootfy. Ela roda ao abrir a janela de venda ou de compra e alimenta o checkbox e o botão.

  1. O gatilho. Abrir a janela de venda (venda) ou de compra (showConfimarWindowDone) dispara requestEligibility().

  2. O cache. O resultado é cacheado por 60 segundos por sessão. O botão “Atualizar” força a reconsulta (ignora o cache) — útil para reavaliar depois de vincular ou cadastrar recebimento sem fechar e reabrir a janela.

  3. O pedido. Manda elig@{} no opcode 221; o servidor responde elig@<json> no 220 com {allowed, linked, message, blocker}.

  4. A aplicação, assimétrica. Na venda, o checkbox destrava por allowed — que exige recebedor aprovado, porque o vendedor vai receber dinheiro. Na compra, o botão destrava só por linked — o comprador só precisa estar vinculado; recebedor é regra do vendedor, não dele.

Fluxo 3 — Anúncio registrar anúncio

Seção intitulada “Fluxo 3 — Anúncio ”

O anúncio publica na Lootfy uma oferta que o jogador acabou de criar no market do jogo. A ordem entre criar a oferta e anunciá-la é o que faz funcionar.

  1. O gesto. No ConfVend embrulhado (o botão Vender), o módulo lê antes de tudo se o checkbox “Anunciar na Lootfy” está marcado e habilitado, e sanitiza o preço em reais (só dígitos, vírgula e ponto).

  2. A oferta nasce no jogo. O ConfVend original roda e cria a oferta de market in-game, do jeito normal do jogo.

  3. O anúncio. Se estava anunciando e o preço não é vazio, o módulo manda announce@{"brl":"<preço>"} no opcode 221. Preço vazio aborta com um aviso, sem anunciar.

  4. O Agent lista. Na mesma sessão TCP, a criação da oferta e o announce@ chegam ao servidor em ordem. O Agent pega a oferta recém-criada pela chave estável player_id + time e a registra na Lootfy (registrar anúncio, POST /v1/api/market/listings, signature-only).

Fluxo 4 — Compra criar transação

Seção intitulada “Fluxo 4 — Compra ”

A compra cria uma transação a partir da oferta que o comprador selecionou e devolve a ele uma página de pagamento Pix.

  1. O gesto. O clique no botão “Comprar na Lootfy (R$)” resolve a oferta selecionada no market e lê a quantidade do campo da janela.

  2. O pedido. Manda buy@{"seller":..,"clientId":..,"count":..,"qty":..} no opcode 221. Ele envia o clientId do item (o servidor casa por getItemInfo().clientId, id exato, porque o nome de exibição poderia divergir) e o count total da oferta como desempate — para quando o vendedor tem mais de um anúncio do mesmo item.

  3. O debounce. O botão se desabilita no clique e só reabilita quando chega o checkout@ ou após 5 segundos. Cada clique é um jti novo, uma transação nova — o debounce evita que um duplo clique vire duas compras.

  4. O servidor e o Agent. O opcode.lua valida contra o cid, monta a oferta de compra (item, personagem, quantidade — sem preço, que a plataforma já conhece do anúncio) e o Agent faz POST /v1/api/transactions (criar transação, signature-only). O jti aqui é chave de idempotência: um retry reusa o mesmo.

  5. A volta. A plataforma devolve o checkoutUrl; o servidor manda checkout@<url> no opcode 220 e o módulo abre a página de pagamento no navegador do jogador. O debounce solta.

Fluxo 5 — Entrega server-side

Seção intitulada “Fluxo 5 — Entrega ”

A entrega acontece depois e fora do client — é toda server-side, disparada pelo webhook de pagamento. O jogador não faz nada; ele só recebe o item.

  1. O pagamento confirma. O comprador paga o Pix no navegador. O PSP confirma e a Lootfy dispara o webhook de entrega transfer_order, assinado com a chave da plataforma.

  2. O Agent verifica. O Agent valida a assinatura do webhook (chave PLATFORM) e aciona o Lua de entrega do servidor.

  3. A engine entrega. O Lua chama doLootfyDeliver(sellerId, offerTime, count, buyerName) — o patch de engine. A oferta é encontrada pela chave estável, o estoque é consumido na memória e realinhado no banco, e o item vai para a bag (comprador online) ou o depot (offline). Nenhum dinheiro do jogo se move.

  4. A confirmação. O Lua lê o (code, remaining) retornado: 0 confirma a entrega à plataforma via POST /v1/api/transactions/{transactionId}/delivery (confirmar entrega); 2 (estoque insuficiente) ou 1 (oferta sumiu) reportam a falha via POST /v1/api/transactions/{transactionId}/delivery-failure (reportar falha de entrega), e a plataforma trata (estorno ou reenfileiramento).