Not translated yet — showing English.
Entity presets
A preset is a named bundle of entity aspects — data, states, RPC, events, hooks — packaged for one game case. You apply a preset, tune its numbers, or derive your own. Applying one adds aspects to your type; it does not put your type underneath anything — a preset is not a module and has nothing of its own to inherit from. Stats, abilities, projectiles, drop tables and world objects are five presets, not five subsystems: the same declaration, the same sync, the same hook order.
When to use it
- A thing in your game carries numbers that clamp, regenerate, and fire a transition at their bounds.
- An action needs cost, cooldown, phases and effects, reachable from one client verb.
- Something goes in flight, and its hit must be judged fairly for a lagged shooter.
- Loot must come from weighted odds that replay exactly when a player disputes a drop.
- The map has furniture — doors, buttons, traps, destructibles — with states that must survive a mid-round join.
- Skip presets when an entity is plain synced data. Declare the fields and stop.
Who does what
| Actor | On this page |
|---|---|
schema-author | declares stats, abilities, projectiles, drop tables, world objects |
room-owner | tunes preset numbers, rolls drop tables, creates world objects |
player | casts abilities, fires shots, picks up loot, interacts with objects |
At a glance
Crate from two shipped presets, then create one per line and tune it to 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})Attribute-style declaration in Go is still open (O-1) — the samples land when the carrier is decided.
// 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.// 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);The model
A preset introduces no new notions. Everything it adds is expressible by the means entity already gives — aspects, machines, hooks, persistence.
What each preset gives, and where it is tuned.
| Preset | What the contract gives it | Where it is tuned |
|---|---|---|
stats | an aspect of numeric characteristics with bounds, regeneration and modifiers, plus a hook on reaching a threshold — 0 HP becomes a machine transition rather than an if in your code | the field's declaration; the numbers stay live-editable in the panel |
abilities | an aspect of a set of abilities, a machine of application phases, and cost and cooldown | the ability's declaration |
projectiles | a type with runtime persistence, a ballistics aspect, and a hit event | the projectile's declaration — one attribute swap changes the flight model |
drops | an aspect of a drop table with weights, and a hook after death | the table's entries and weights |
world objects | a state machine of an interactive object, and an aspect of the interaction condition | the preset's declaration, or per instance at creation |
| inventory | an owned type with a ref to a catalog item, a stack aspect with an increment, and a per-owner cap with declared overflow | the type's declaration |
Inventory also has a page of its own.
What is true of every preset.
| Always | What it is |
|---|---|
where it sits | on an entity, as aspects: its data syncs like any other data, its states are entity states, its RPCs are entity RPCs, and its hooks run in entity hook order |
tuning | is live config rather than a redeploy, which is why the panel shows a stat bound, a cooldown and a drop weight in one tree |
deriving your own | is composition, not subclassing: Crate is world-objects plus stats, and the derived thing is still aspects on an entity |
Errors
- Declaring a stat, an ability, a projectile, a drop table or a world object is a schema act —
fnoradm. A player or client key attempting one getsforbidden, and nothing is declared or half-declared. That is a different refusal from the ones a player meets inside a call they were allowed to make — on cooldown, cannot pay, a missingitem:key.bronze— each of which carries its own code.
The rest of a preset's refusals are entity's. Two are specific to presets:
- A partially filled preset is a validation failure at deploy. A preset carries a coherent set: half a declaration is refused before it ships rather than behaving oddly in a match.
- A preset cannot be marked with a property its own mechanics contradict — an aspect the client has no rules for cannot be declared predictable, and that too is caught at deploy.
Limits
The ceilings are entity's — aspects per type, machines per type, the stored instance's size, the rate of changes to one instance. The one a preset declares itself is the per-owner cap an owned preset carries, with one of three boundary behaviours and no default: refuse · redirect into a declared owner bucket · discard with event. The numbers arrive with the platform limits chapter.