Aller au contenu principal
Le modèle de votre jeu

Cette page n’est pas encore traduite : la version anglaise est affichée.

Entity presets

Un preset regroupe sous un nom des aspects d’entité — données, états, RPC, événements, hooks — pensés pour un cas de jeu précis. Vous appliquez un preset tel quel, vous ajustez ses valeurs ou vous en dérivez le vôtre. Appliquer un preset ajoute des aspects à votre type, sans placer ce type sous quoi que ce soit : un preset n’est pas un module et n’a rien en propre dont on pourrait hériter. Statistiques, capacités, projectiles, tables de butin et objets du monde sont cinq presets, pas cinq sous-systèmes : même déclaration, même synchronisation, même ordre des hooks.

Quand l’utiliser

  • Un élément de votre jeu porte des valeurs bornées, qui se régénèrent et déclenchent une transition quand elles atteignent leurs limites.
  • Une action a besoin d’un coût, d’un temps de recharge, de phases et d’effets, le tout accessible par un seul verbe côté client.
  • Quelque chose part en vol, et son impact doit être jugé équitablement pour un tireur qui subit de la latence.
  • Le butin doit sortir de probabilités pondérées qui se rejouent à l’identique quand un joueur conteste un tirage.
  • La carte contient du mobilier — portes, boutons, pièges, objets destructibles — dont les états doivent survivre à l’arrivée d’un joueur en cours de manche.
  • Inutile si une entité n’est qu’un ensemble de données synchronisées. Déclarez les champs, c’est tout.

Qui fait quoi

ActeurCe qu’il fait sur cette page
schema-authordéclare les statistiques, les capacités (ability), les projectiles, les tables de butin et les objets du monde
room-ownerajuste les valeurs des presets, effectue les tirages dans les tables de butin, crée les objets du monde
playerlance des capacités, tire, ramasse le butin, interagit avec les objets

En bref

Dériver Crate de deux presets fournis, puis créer chaque caisse en une ligne et la régler à 250 PV
// 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})
Bientôt — Go

La déclaration par attributs en Go n’est pas encore tranchée (O-1). Les exemples arriveront quand la forme d’écriture sera choisie.

// 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 — la même déclaration C# ; la création relève de l’hôte de la salle, et un client Unity voit la caisse apparaître
// 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);

Le modèle

Un preset n’introduit aucune notion nouvelle. Tout ce qu’il ajoute s’exprime avec les moyens que fournit déjà l’entité — aspects, machines, hooks, persistance.

Ce qu’apporte chaque preset, et où il se règle.

PresetCe que lui apporte le contratOù il se règle
statsun aspect de caractéristiques numériques avec bornes, régénération et modificateurs, plus un hook au franchissement d’un seuil — 0 HP devient une transition de machine à états plutôt qu’un if dans votre codela déclaration du champ ; les valeurs restent modifiables à chaud dans le panneau
abilitiesun aspect regroupant un ensemble de capacités, une machine à états des phases d’application, un coût et un temps de rechargela déclaration de la capacité
projectilesun type à persistance runtime, un aspect de balistique et un événement d’impactla déclaration du projectile — changer un seul attribut change le modèle de vol
dropsun aspect de table de butin (drop table) pondérée, et un hook après la mortles entrées de la table et leurs poids
world objectsla machine à états d’un objet interactif, et un aspect pour la condition d’interactionla déclaration du preset, ou instance par instance à la création
inventoryun type possédé par un propriétaire, avec une ref vers un objet du catalogue, un aspect de pile avec incrément, et un plafond par propriétaire avec un comportement de débordement déclaréla déclaration du type

Inventory a aussi sa propre page.

Ce qui vaut pour tout preset.

ToujoursCe que c’est
où il se placesur une entité, sous forme d’aspects : ses données se synchronisent comme toutes les autres, ses états sont des états de l’entité, ses RPC sont des RPC de l’entité, et ses hooks s’exécutent dans l’ordre des hooks de l’entité
réglagerelève de la configuration à chaud, pas d’un redéploiement. C’est pourquoi le panneau affiche la borne d’une statistique, un temps de recharge et le poids d’un butin dans le même arbre
dériver le vôtrec’est de la composition, pas de l’héritage : Crate, c’est world-objects plus stats, et le résultat reste un ensemble d’aspects sur une entité

Erreurs

  • Déclarer une statistique, une capacité, un projectile, une table de butin ou un objet du monde est un acte de schéma — fn ou adm. Une clé joueur ou client qui s’y essaie reçoit forbidden, et rien n’est déclaré, même à moitié. Ce refus diffère de ceux qu’un joueur rencontre dans un appel qu’il avait le droit de faire — temps de recharge en cours, paiement impossible, item:key.bronze manquant — et qui portent chacun leur propre code.

Les autres refus d’un preset sont ceux de l’entité. Deux sont propres aux presets :

  • Un preset partiellement rempli échoue à la validation au déploiement. Un preset porte un ensemble cohérent : une déclaration à moitié faite est refusée avant de partir en production, au lieu de se comporter bizarrement en plein match.
  • Un preset ne peut pas recevoir une propriété que ses propres mécaniques contredisent — un aspect pour lequel le client n’a pas de règles ne peut pas être déclaré prédictible, et cela aussi est détecté au déploiement.

Limites

Les plafonds sont ceux de l’entité — aspects par type, machines par type, taille de l’instance stockée, fréquence des modifications d’une instance. Le seul qu’un preset déclare lui-même est le plafond par propriétaire que porte un preset possédé, avec l’un des trois comportements à la limite et aucune valeur par défaut : refuse · redirect vers un compartiment de propriétaire déclaré · discard with event. Les valeurs chiffrées arriveront avec le chapitre sur les limites de la plateforme.