Перейти до основного вмісту
Модель гри

Цю сторінку ще не перекладено — показано англійську версію.

Entity presets

Пресет — це іменований набір аспектів сутності — даних, станів, RPC, подій, хуків, — зібраний під один ігровий сценарій. Пресет можна застосувати, підлаштувати його числа або вивести з нього власний. Застосований пресет додає аспекти до вашого типу, але не ставить ваш тип нижче за щось в ієрархії: пресет — не модуль, і успадковувати в ньому нічого. Характеристики, здібності, снаряди, таблиці випадання та об’єкти світу — це п’ять пресетів, а не п’ять підсистем: те саме оголошення, та сама синхронізація, той самий порядок хуків.

Коли це потрібно

  • У вашій грі є об’єкт із числами, які не виходять за межі, відновлюються й запускають перехід, коли досягають межі.
  • Дії потрібні вартість, перезаряджання (cooldown), фази та ефекти, і клієнт має запускати її однією командою.
  • Щось летить, і влучання треба чесно оцінити навіть для стрільця з лагом.
  • Здобич має випадати за зваженими шансами, які точно відтворюються, коли гравець оскаржує випадання.
  • На мапі є обладнання — двері, кнопки, пастки, руйновані об’єкти, — стани якого мають зберегтися, коли гравець приєднується посеред раунду.
  • Пресети не потрібні, коли сутність (entity) — це просто синхронізовані дані. Оголосіть поля, і цього досить.

Хто що робить

АкторЩо робить на цій сторінці
schema-authorоголошує характеристики, здібності, снаряди, таблиці випадання, об’єкти світу
room-ownerналаштовує числа пресетів, кидає жереб за таблицями випадання, створює об’єкти світу
playerзастосовує здібності, стріляє, підбирає здобич, взаємодіє з об’єктами

Коротко

Виводимо Crate з двох готових пресетів, потім створюємо ящик одним рядком і налаштовуємо його на 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})
Незабаром — Go

Як оголошувати через атрибути в Go, поки не вирішено (O-1). Приклади з’являться, коли оберуть спосіб запису.

// 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 — те саме оголошення C#; створення доступне в інтерфейсі хоста кімнати, а клієнт Unity бачить, як з’являється ящик
// 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);

Модель

Пресет не вводить нових понять. Усе, що він додає, можна виразити засобами, які вже дає сутність: аспектами, машинами станів, хуками, зберіганням.

Що дає кожен пресет і де його налаштовують.

ПресетЩо дає йому контрактДе налаштовують
statsаспект числових характеристик (stat) з межами, відновленням і модифікаторами, а також хук на досягнення порога: 0 HP стає переходом машини станів, а не if у вашому кодіоголошення (declaration) поля; числа можна змінювати наживо в панелі
abilitiesаспект із набором здібностей (ability), машина фаз застосування, вартість і перезаряджанняоголошення здібності
projectilesтип із режимом зберігання runtime, аспект балістики й подія (event) влучанняоголошення снаряда: заміна одного атрибута змінює модель польоту
dropsаспект таблиці випадання (drop table) з вагами і хук після смертізаписи таблиці та їхні ваги
world objectsмашина станів (state machine) інтерактивного об’єкта й аспект умови взаємодіїоголошення пресета або кожен екземпляр окремо під час створення
inventoryтип із власником, який тримає ref на предмет каталогу (catalog), аспект стосу з інкрементом і ліміт на власника з оголошеною поведінкою при переповненніоголошення типу

В Inventory є й окрема сторінка.

Що справджується для кожного пресета.

ЗавждиЩо це
де він живена сутності, у вигляді аспектів: його дані синхронізуються, як будь-які інші дані, його стани — це стани сутності, його RPC — це RPC сутності, а його хуки виконуються в порядку хуків сутності
налаштуванняце жива конфігурація, а не повторний деплой. Тому панель показує межу характеристики, перезаряджання й вагу випадання в одному дереві
власний пресетвиводять композицією, а не успадкуванням: Crate — це world-objects плюс stats, і результат однаково лишається аспектами на сутності

Помилки

  • Оголосити характеристику, здібність, снаряд, таблицю випадання чи об’єкт світу означає змінити схему (schema), тому потрібен fn або adm. Якщо таке оголошення спробує зробити ключ гравця чи клієнта, він отримає forbidden, і нічого не буде оголошено ні повністю, ні наполовину. Це інша відмова, ніж ті, що трапляються гравцеві всередині виклику, який йому дозволено зробити: перезаряджання ще триває, нема чим заплатити, бракує item:key.bronze. Кожна з них має власний код.

Решта відмов пресета — це відмови сутності. Дві стосуються саме пресетів:

  • Частково заповнений пресет не проходить валідацію під час деплою. Пресет містить узгоджений набір: половину оголошення платформа відхиляє ще до випуску, а не дає їй дивно поводитися в матчі.
  • Пресет не можна позначити властивістю, яка суперечить його власній механіці. Наприклад, аспект, для якого в клієнта немає правил, не можна оголосити передбачуваним, і це теж виявляється під час деплою.

Обмеження

Стелі тут ті самі, що й у сутності: кількість аспектів і машин станів на тип, розмір збереженого екземпляра, частота змін одного екземпляра. Сам пресет оголошує лише ліміт на власника, який несе пресет із власником. Він має одну з трьох поведінок на межі й не має значення за замовчуванням: refuse · redirect в оголошений кошик власника · discard with event. Конкретні числа з’являться разом із розділом про ліміти платформи.