Pular para o conteúdo principal
O modelo do seu jogo

Esta página ainda não foi traduzida: mostrando a versão em inglês.

Entity presets

Um preset é um pacote nomeado de aspectos de entidade — dados, estados, RPC, eventos, hooks — montado para uma situação concreta do jogo. Você aplica um preset, ajusta os números dele ou deriva o seu. Aplicar um preset adiciona aspectos ao seu tipo, mas não coloca o seu tipo embaixo de nada: um preset não é um módulo e não tem nada próprio de que herdar. Stats, habilidades (ability), projéteis, tabelas de drops e objetos do mundo são cinco presets, e não cinco subsistemas: a mesma declaração, a mesma sincronização, a mesma ordem de hooks.

Quando usar

  • Algo no seu jogo tem números que ficam dentro de limites, se regeneram e disparam uma transição quando chegam a esses limites.
  • Uma ação precisa de custo, cooldown, fases e efeitos, acionados por um único verbo do cliente.
  • Algo está em voo, e o acerto precisa ser julgado com justiça para quem atira com lag.
  • O loot precisa vir de probabilidades com pesos que se reproduzem exatamente quando um jogador contesta um drop.
  • O mapa tem elementos de cenário — portas, botões, armadilhas, objetos destrutíveis — com estados que precisam sobreviver à entrada de alguém no meio da rodada.
  • Dispensável quando a entidade é só um conjunto de dados sincronizados. Declare os campos e pronto.

Quem faz o quê

AtorO que faz nesta página
schema-authordeclara stats, habilidades, projéteis, tabelas de drops e objetos do mundo
room-ownerajusta os números dos presets, sorteia nas tabelas de drops, cria objetos do mundo
playerusa habilidades, atira, pega loot, interage com objetos

Resumo

Derive Crate de dois presets prontos e depois crie cada caixa com uma linha, ajustada para 250 HP
// derived once, in the schema
[Entity("crate", Persistence = Persistence.Runtime, Presets = new[] { Preset.WorldObjects, Preset.Stats })]
public class Crate { [Stat(Max = 100, AtMin = "broken")] public Stat Hp; }

// then one line per crate, on the room host
var crate = await room.Create<Crate>(at: pos, tune: c => c.Hp.Max = 250);
// derived once, in the schema
@Entity('crate', { persistence: Persistence.Runtime, presets: [Preset.WorldObjects, Preset.Stats] })
export class Crate { @Stat({ max: 100, atMin: 'broken' }) hp: Stat; }

// then one line per crate, on the room host
const crate = await room.create<Crate>({ at: pos, tune: (c) => { c.hp.max = 250; } });
# derived once, in the schema
@entity("crate", persistence=Persistence.RUNTIME, presets=[Preset.WORLD_OBJECTS, Preset.STATS])
class Crate:
    hp = stat(max=100, at_min="broken")

# then one line per crate, on the room host
crate = await room.create(Crate, at=pos, tune={"hp.max": 250})
Em breve — Go

Ainda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.

// declarations compile into the same pushed model — playserv push from the UE project or CI
UCLASS(PSEntity = (Name = "crate", Persistence = "Runtime", Presets = "world-objects, stats"))
class UCrate : public UObject
{
    GENERATED_BODY()

    UPROPERTY(PSStat = (Max = 100, AtMin = "broken")) FPSStat Hp;
};

// then one line per crate, on the room host (dedicated server / master-client)
Room->Entities->Of<UCrate>()->Create(FPSIdempotencyKey(CrateId),
    [SpawnPosition](UCrate& Crate) { Crate.Position = SpawnPosition; });   // Position — from the world-objects preset
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.
Unity C# is the same C# API here — a mesma declaração C#. Criar instâncias cabe ao host da sala (room), e um cliente Unity vê a caixa aparecer
// derived once, in the schema
[Entity("crate", Persistence = Persistence.Runtime, Presets = new[] { Preset.WorldObjects, Preset.Stats })]
public class Crate { [Stat(Max = 100, AtMin = "broken")] public Stat Hp; }

// then one line per crate, on the room host
var crate = await room.Create<Crate>(at: pos, tune: c => c.Hp.Max = 250);

O modelo

Um preset não introduz nenhum conceito novo. Tudo o que ele adiciona pode ser expresso com os recursos que a entidade já oferece — aspectos, máquinas de estados, hooks, persistência.

O que cada preset oferece e onde ele é ajustado.

PresetO que o contrato ofereceOnde é ajustado
statsum aspecto de características numéricas com limites, regeneração e modificadores, mais um hook ao atingir um limiar — 0 HP vira uma transição da máquina de estados, e não um if no seu códigoa declaração do campo. Os números continuam editáveis ao vivo no painel
abilitiesum aspecto com um conjunto de habilidades, uma máquina de estados das fases de uso, além de custo e cooldowna declaração da habilidade
projectilesum tipo com persistência runtime, um aspecto de balística e um evento de acertoa declaração do projétil — trocar um único atributo muda o modelo de voo
dropsum aspecto de tabela de drops com pesos e um hook depois da morteas entradas e os pesos da tabela
world objectsuma máquina de estados de objeto interativo e um aspecto com a condição de interaçãoa declaração do preset, ou cada instância na criação
inventoryum tipo com dono, com uma ref para um item do catálogo, um aspecto de pilha com incremento e um teto por dono com comportamento declarado para o excedentea declaração do tipo

Inventory também tem uma página própria.

O que vale para todo preset.

SempreO que é
onde ele ficaem uma entidade, como aspectos: os dados dele sincronizam como quaisquer outros, os estados são estados da entidade, os RPCs são RPCs da entidade e os hooks rodam na ordem de hooks da entidade
ajusteé configuração ao vivo, e não um novo deploy. Por isso o painel mostra o limite de um stat, um cooldown e o peso de um drop na mesma árvore
derivar o seué composição, e não criação de subclasse: Crate é world-objects mais stats, e o resultado continua sendo um conjunto de aspectos em uma entidade

Erros

  • Declarar um stat, uma habilidade, um projétil, uma tabela de drops ou um objeto do mundo é uma operação de esquema — fn ou adm. Uma chave de jogador ou de cliente que tente fazer isso recebe forbidden, e nada fica declarado, nem pela metade. Essa recusa é diferente das que um jogador encontra dentro de uma chamada que ele tinha permissão para fazer — cooldown ativo, saldo insuficiente, falta do item:key.bronze —, e cada uma delas traz o próprio código.

As demais recusas de um preset são as da entidade. Duas são específicas dos presets:

  • Um preset preenchido pela metade é uma falha de validação no deploy. Um preset traz um conjunto coerente: uma declaração pela metade é recusada antes de ir para produção, em vez de se comportar de um jeito estranho no meio de uma partida.
  • Um preset não pode ser marcado com uma propriedade que a própria mecânica dele contradiz — um aspecto para o qual o cliente não tem regras não pode ser declarado com predição, e isso também é detectado no deploy.

Limites

Os tetos são os da entidade — aspectos por tipo, máquinas de estados por tipo, o tamanho da instância armazenada, a taxa de mudanças em uma instância. O único que o próprio preset declara é o teto por dono de um preset com dono, com um de três comportamentos na fronteira e sem padrão: refuse · redirect para um compartimento declarado do dono · discard with event. Os números chegam com o capítulo sobre os limites da plataforma.