Esta página ainda não foi traduzida: mostrando a versão em inglês.
Esquema como código
Declare o modelo em código, publique e receba os tipos de volta. É por aqui que o desenvolvedor chega ao esquema: o painel de administração e o código editam o mesmo modelo, e a geração de código fecha o ciclo para cada engine.
Quando usar
- O modelo de dados deve morar no código e passar por revisão como código: declare,
schema diff,schema push. - Os tipos da engine nunca podem se afastar do modelo publicado:
schema codegengera de novo o código Unreal C++ e Unity C#. - Uma mudança incompatível precisa poder ser lida e cancelada antes de rodar: propor → planejar → aplicar.
- Você reaproveita o mesmo pacote (
Stat,Interactable) em vários projetos: declare-o uma vez como preset. - Dispensável quando um operador só ajusta valores no painel de administração. Mesmo assim, a mudança no modelo aparece no diff contra o código.
Quem faz o quê
| Ator | O que faz nesta página |
|---|---|
schema-author | declara entidades, partes e enums em código, faz o diff e publica |
operator | revisa a visão geral no painel, propõe e aplica migrações |
ci | o pipeline de build, rodando com uma chave backend-service: publica a cada merge e depois gera de novo os tipos da engine |
Resumo
Item com uma parte Stats embutida e um enum, publicados como um único esquema[Entity("item")]
public class Item
{
public string Name = "";
public Rarity Rarity; // an enum declared the same way
public Stats Stats = new(); // a part — embedded, no lifecycle of its own
}
[Part("stats")]
public class Stats { public int Power; public int Weight; }@Entity('item')
export class Item {
name = '';
rarity!: Rarity; // an enum declared the same way
stats = new Stats(); // a part — embedded, no lifecycle of its own
}
@Part('stats')
export class Stats { power = 0; weight = 0; }@entity("item")
class Item:
name: str = ""
rarity: Rarity # an enum declared the same way
stats: Stats = Stats() # a part — embedded, no lifecycle of its own
@part("stats")
class Stats:
power: int = 0
weight: int = 0Ainda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.
USTRUCT(PSPart = "stats")
struct FItemStats
{
GENERATED_BODY()
UPROPERTY() int32 Power;
UPROPERTY() int32 Weight;
};
UCLASS(PSEntity = "item")
class UItem : public UObject
{
GENERATED_BODY()
UPROPERTY() FString Name;
UPROPERTY() EPSRarity Rarity; // an enum declared the same way
UPROPERTY() FItemStats Stats; // a part — embedded, no lifecycle of its own
};
// declarations compile into the same pushed model — playserv push from the UE project or CI[Entity("item")]
public class Item
{
public string Name = "";
public Rarity Rarity; // an enum declared the same way
public Stats Stats = new(); // a part — embedded, no lifecycle of its own
}
[Part("stats")]
public class Stats { public int Power; public int Weight; }playserv schema diff # local declarations vs deployed schema
playserv schema push # with a revision precondition — no blind overwrites
playserv schema codegen # regenerate Unreal C++ / Unity C# types
A publicação é um passo explícito
Salvar um arquivo não envia nada. Uma declaração só chega ao modelo publicado quando playserv push (ou schema push) roda, na sua máquina ou no CI, e leva junto a revisão contra a qual o diff foi calculado. Uma edição feita no painel aparece como divergência em schema diff. Nos dois sentidos, a mudança só passa de um lado para o outro quando você executa um comando.
O modelo
O que uma declaração carrega.
| Carrega | O que é |
|---|---|
key | o nome estável pelo qual ela é referenciada. Renomear no código é uma renomeação, e não uma exclusão seguida de criação |
kind | uma entidade, uma parte ou um enum, declarados em código |
modo de posse | seed: o código cria o registro se ele não existir, e uma nova publicação não mexe nos valores, que a partir daí pertencem ao console de administração. Ou managed: o código é sempre o dono, cada publicação leva os valores de volta ao que está declarado, e edições feitas no console de administração são recusadas, em vez de aplicadas e perdidas na publicação seguinte |
preset | opcional: um pacote reutilizável — um preset de entidade, como stats ou world-objects — declarado uma vez e aplicado como um tipo. Não cria nenhum tipo novo de declaração |
O que uma publicação garante.
| Sempre | O que é |
|---|---|
correspondência | é feita pela chave, nunca pelo símbolo: publicar de novo depois de renomear o símbolo deixa um registro, e não dois |
o relatório | diz exatamente o que vai mudar antes de aplicar e, depois, o que foi sobrescrito |
origem | é identificável: um registro criado por uma publicação a partir do código se distingue de um criado em outro lugar |
a revisão | vai junto com a publicação, que é aplicada inteira ou não é aplicada |
O que a geração de código garante.
| Sempre | O que é |
|---|---|
regeneração | acontece depois de cada publicação, e os tipos gerados nunca são editados à mão: gerar de novo e depois fazer o diff não produz nenhuma mudança |
nomes | seguem a declaração, onde quer que ela tenha sido escrita — o campo Rarity de Item vira UPSItem::Rarity no Unreal e Item.Rarity no Unity |
os dois sentidos | não se separam: tudo o que é declarado no código aparece no painel, e tudo o que um operador cria no painel gera um diff limpo contra o código. Por isso schema diff mostra todas as diferenças |
O que uma migração garante.
| Sempre | O que é |
|---|---|
quando é necessária | quando uma mudança em uma declaração persistente reescreve valores existentes |
o que ela declara | uma versão, uma prévia, uma aplicação em ordem, um rollback em caso de falha e um resultado final observável |
coexistência | enquanto duas versões dos dados estão ativas, leituras e escritas declaram quais versões aceitam — o runtime nunca deduz compatibilidade a partir dos nomes dos campos |
Erros
- Quem chama sem o papel (role) recebe
forbidden, e o modelo publicado fica intacto: uma recusa nunca é uma publicação parcial. Essa recusa é diferente da revisão desatualizada, que vem comoprecondition_failede significa que o diff foi calculado contra um esquema que mudou desde então. Faça o diff de novo e publique outra vez. - Um valor fora de um limite declarado é recusado na escrita, e nunca ajustado ao limite. O mesmo vale para uma string maior que o comprimento declarado. Ajustar o valor ao limite produziria um valor válido — e errado.
- Uma sequência UTF-8 inválida é rejeitada na escrita, e não corrigida.
- Uma mudança persistente incompatível sem migração declarada não pode ser publicada de jeito nenhum.
Limites
Os tetos que dependem da forma da declaração são verificados no momento da declaração — no deploy ou na publicação — e não no primeiro uso, sempre que o sintoma em runtime não pareceria uma recusa. Os números chegam com o capítulo sobre os limites da plataforma.