Перейти до основного вмісту
Сервіси навколо гри

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

Inventory

Один набір рядків із власником, яким користуються постріли, випадання, здібності й переміщення. Стоси змінюються інкрементом, а ліміт на власника поводиться на межі так, як оберете ви.

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

  • Гравці володіють речами, і кожна така річ — рядок інвентарю (inventory) з власником. Його читають за власником, кількість рядків обмежено для кожного власника, а поведінку при переповненні оголошують явно, а не беруть за замовчуванням.
  • Кількість накопичується: стос (stack) змінюється інкрементом. Інкремент несе ключ ідемпотентності, тож повторне списання не спише двічі.
  • Інші модулі витрачають з одного набору: постріли списують набої, випадання дає здобич, а покупки з’являються рядками, прив’язаними до права володіння (entitlement).
  • Не знадобиться, якщо цим числом не можна володіти. HP, XP і перезаряджання належать до характеристик (stat).

Хто що робить

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

Коротко

Код з авторитетністю fn: видати набої, перемістити предмет у слот спорядження primary і перед витратою перевірити, чи вистачає ресурсу
// fn authority — a cloud function, or a dedicated server holding a host key
var bag = await player.Inventory.Container("bag");
var equipment = await player.Inventory.Container("equipment");

await player.Inventory.Grant("ammo.shell", count: 20);
await bag.Move(itemId, to: equipment, slot: "primary");

if (await player.Inventory.CanAfford("ammo.shell", 1))
    await player.Inventory.Consume("ammo.shell", 1);
// fn authority — a cloud function, or a dedicated server holding a host key
const bag = await player.inventory.container('bag');
const equipment = await player.inventory.container('equipment');

await player.inventory.grant('ammo.shell', { count: 20 });
await bag.move(itemId, { to: equipment, slot: 'primary' });

if (await player.inventory.canAfford('ammo.shell', 1))
  await player.inventory.consume('ammo.shell', 1);
# fn authority — a cloud function, or a dedicated server holding a host key
bag = await player.inventory.container("bag")
equipment = await player.inventory.container("equipment")

await player.inventory.grant("ammo.shell", count=20)
await bag.move(item_id, to=equipment, slot="primary")

if await player.inventory.can_afford("ammo.shell", 1):
    await player.inventory.consume("ammo.shell", 1)
Незабаром — Go

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

// fn authority — a cloud function, or a dedicated server holding a host key
Client->Commerce->Entitlements->Grant(FPSIdempotencyKey(GrantId), PlayerId, PSKeys::Item::AmmoShell);

// spending is an instance act on the entitlement you hold
Entitlement->Spend(FPSIdempotencyKey(SpendId), /*Amount*/ 1,
    TPSOnResult<void>::CreateLambda([](const TPSResult<void>& Result)
    {
        // short on the item is a declared refusal, not a silent no-op
        if (Result.IsRefused()) { DeclineReload(Result.Refusal()); }
    }));
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.
// fn authority — a cloud function, or a dedicated server holding a host key
var bag = await player.Inventory.Container("bag");
var equipment = await player.Inventory.Container("equipment");

await player.Inventory.Grant("ammo.shell", count: 20);
await bag.Move(itemId, to: equipment, slot: "primary");

if (await player.Inventory.CanAfford("ammo.shell", 1))
    await player.Inventory.Consume("ammo.shell", 1);

Сесія гравця виконує читання, переміщення й перевірку ресурсу тими самими викликами. А от видавати, витрачати й знищувати вона не може: платформа відхиляє такі виклики як заборонені й називає право, якого бракує викликачеві, — незалежно від того, з якого біндингу надійшов виклик.

Модель

Власних понять інвентар не вводить. Це пресет — форма, зібрана з того, що вже дає сутність. Тому все, що описано нижче, — оголошення сутності, а не механізми цієї сторінки.

ОголошенняЩо це
тип із власникомзапис про володіння належить власникові, а вибірка за власником — це власна операція сутності (entity)
ref на предмет каталогупосилання зберігає id предмета, а не його key, тож ключ можна безпечно перейменувати. Саме визначення предмета живе в модулі Catalog & Commerce
аспект стосу з інкрементомстос змінюється на дельту, а не перезаписом прочитаного значення (див. нижче)
ліміт на власника з поведінкою на межіодин із трьох варіантів, і типового немає: refuse · redirect в оголошений кошик власника · discard with event

Передавайте ключ ідемпотентності з кожним інкрементом

Інкремент не ідемпотентний: два інкременти — це два інкременти. Без ключа ідемпотентності повторне списання спише двічі. Щоб дізнатися результат, прочитайте потрібний запис за його адресою.

a grant arrives; the owner is at the capthe cap's declared behaviour (no default)the loot stays where it wasinto a declared owner bucketgone, with an event refuseredirectdiscard with event
Видача в повну сумку: вирішує оголошена поведінка ліміту, типового варіанта немає

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

ЗавждиЩо це
у ліміту немає типового значеннятри відповіді на повну сумку — це три різні гри. Відмова лишає здобич лежати перед гравцем. Перенаправлення — це пошта або переповнений склад. Відкидання — тиха втрата, прийнятна лише тому, що її оголошено і її видно. Жоден варіант не підходить усім трьом іграм, тому вибір робить оголошення
власник незміннийправкою поля нічого з рук у руки не переходить: запис переходить як відкликання плюс нова видача з оголошеним джерелом, і обидва факти лишаються в історії
передача між двома гравцями— це інша обіцянка: вона потребує ескроу й захисту від шахрайства і в цю версію не входить
рядоквідображає право володіння, а не є його другим джерелом: куплене живе в модулі Catalog & Commerce, а рядок тут лише його представляє

Помилки

  • Екземпляра не існує або його приховує предикат: в обох випадках відповідь not found, тож відмова ніколи не видає, що щось існує, але належить не вам.
  • Поле, не оголошене в аспекті (зокрема вкладене), і обов’язкове поле без значення — це відмови валідації, у яких названо поле.
  • Версія не збіглася — це невиконана передумова; перечитайте запис і повторіть.
  • Запис від імені гравця, у якому гравця не вказано, — це відмова валідації, а не тихий запис від чужого імені.
  • Немає дозволу на читання чи запис — відповідь forbidden, причому читання й запис розрізняються.

Обмеження

Конкретні числа з’являться в розділі про ліміти платформи, а що відбувається на кожній межі, визначено вже зараз.

  • Екземпляри на власника: за оголошеним вище правилом; типового варіанта немає.
  • Розмір збереженого екземпляра: запис відхиляють як конфлікт, і у відмові названо поле-порушника та виміряний розмір. До межі доходять поступово, накопиченням, тож наближення до неї видно ще до запису, який не пройде.
  • Частота змін одного екземпляра: відмова через обмеження частоти з указаним терміном.
  • Розмір сторінки вибірки (selection): сторінку обрізають до ліміту, а прапорець „є ще“ лишається піднятим. Повертати менше без цього прапорця заборонено.