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

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

Auth & Players

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

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

  • Гравці (player) мають входити в гру: через пристрій, email, Apple, Google, Steam або власний провайдер. Щоб гравця створювало під час першого входу (sign-in), досить прапорця — окремий сценарій не потрібен.
  • Гостьовий акаунт згодом треба перетворити на постійний: Link додає Steam і зберігає прогрес, а об’єднання (merge) зводить два акаунти в одного гравця.
  • Правила мають виконуватися там, де їх не обійти: перевірка регіону перед входом, стартовий набір після того входу, що створив гравця.
  • Модерація має діяти одразу: відкликати сесії, тимчасово блокувати, банити пристрій. Подію (event) banned чує кожна запущена система.
  • Оголошений контекст (регіон, платформа, збірка) має доходити до кожного наступного хука, щоб жоден із них не перечитував гравця лише заради цього.
  • Полегшеної альтернативи немає. Усі інші модулі визначають, хто їх викликає, саме через цей модуль, тому auth не вимкнути, поки хоч одному з них потрібен актор-гравець: конфігуратор модулів відмовить і назве модулі, які від нього залежать.

Хто що робить

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

Коротко

Один виклик SignIn на провайдера, створення гравця під час першого входу вмикає прапорець, Link додає Steam
// client — one call per provider; create-on-first-sign-in is a flag
var session = await PlayServ.Auth.SignIn(Provider.Device, create: true);
await PlayServ.Auth.Link(Provider.Steam);          // one player, many identities
// client — one call per provider; create-on-first-sign-in is a flag
const session = await PlayServ.auth.signIn(Provider.Device, { create: true });
await PlayServ.auth.link(Provider.Steam);    // one player, many identities
# client — one call per provider; create-on-first-sign-in is a flag
session = await playserv.auth.sign_in(Provider.DEVICE, create=True)
await playserv.auth.link(Provider.STEAM)     # one player, many identities
Незабаром — Go

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

// client — one call per provider; create-on-first-sign-in is a flag
Client->Auth->SignInWithProvider(FPSProviderId::Device, Credential,
    TPSOnResult<FPSSession>::CreateWeakLambda(this, [this](const TPSResult<FPSSession>& Result)
    {
        if (!Result.HasValue()) { return; }
        // one player, many identities — add Steam to the same account
        Client->Auth->Providers->Link(FPSProviderId::Steam, SteamCredential);
    }));
// 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 — працює в Unity без змін, зі згенерованими типами
// client — one call per provider; create-on-first-sign-in is a flag
var session = await PlayServ.Auth.SignIn(Provider.Device, create: true);
await PlayServ.Auth.Link(Provider.Steam);          // one player, many identities

Кожну точку налаштовують там, де її оголошено. Усі форми, яких може набувати обробник, зібрано на сторінці Extensibility:

Перевірка перед входом не пускає гравця з певного регіону, а спостерігач після входу, що створив гравця, видає стартовий набір
[Before(Auth.SignIn)]                          // a gate: it may refuse, and it is fail-closed
public static Verdict GateRegion(SignInAttempt a) =>
    a.Region == "sanctioned"
        ? Hook.Reject(Problem.Forbidden, "region not served")
        : Hook.Continue(a);

[After(Auth.SignIn, created: true)]            // an observer: it watches, it cannot refuse
public static async Task GrantStarterPack(Player player)
{
    await player.Inventory.Grant("chest.gold", count: 1);
}
// a gate: it may refuse, and it is fail-closed
export const gateRegion = before(Auth.signIn, (a: SignInAttempt) =>
  a.region === 'sanctioned'
    ? Hook.reject(Problem.forbidden, 'region not served')
    : Hook.continue(a));

// an observer: it watches, it cannot refuse
export const grantStarterPack = after(Auth.signIn, { created: true },
  async (player: Player) => {
    await player.inventory.grant('chest.gold', { count: 1 });
  });
@before(auth.sign_in)                          # a gate: it may refuse, and it is fail-closed
def gate_region(a: SignInAttempt) -> Verdict:
    if a.region == "sanctioned":
        return Hook.reject(Problem.FORBIDDEN, "region not served")
    return Hook.continue_(a)

@after(auth.sign_in, created=True)             # an observer: it watches, it cannot refuse
async def grant_starter_pack(player: Player):
    await player.inventory.grant("chest.gold", count=1)
Незабаром — Go

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

Виконується поза рушієм

І перевизначення, і хук — хмарні функції: вони виконуються на платформі, а не в рушії. Пишіть їх на C#, TypeScript або Python, а Unreal підписується на події, які вони породжують. Функції, написані в самому рушії, заплановано: графи Blueprint і C++ (з трансляцією в скриптовий формат, який перевіряє платформа). Їх аналізують і надсилають на платформу так само, як будь-яке оголошення, а виконуються вони все одно на платформі.

Виконується поза рушієм

І перевизначення, і хук — хмарні функції: вони виконуються на платформі, а не в рушії. Пишіть їх на C#, TypeScript або Python, а Unity підписується на події, які вони породжують.

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

ВидКоли падає сам обробникУ разі відмови
перевірка (gate)платформа відхиляє крок: перевірка регіону, до якої не вдалося достукатися, не вважається пройденоюкод із каталогу платформи й зрозуміла людині причина. Код, що викликає, розгалужується за кодом, а текст причини може змінюватися й перекладатися
спостерігач (observer)крок лишається виконаним: якщо стартовий набір не видано, гравець недорахується скрині, але вхід не зірветьсявідмовити не може

Хук ніколи не вирішує, хто саме ввійшов

Перевірка лише відповідає «так» чи «ні» щодо облікового запису, який платформа вже встановила. Вона не називає гравця, не видає обліковий запис і не заміняє підтвердження від провайдера.

Модель

device · subject (the guest)Steam · subject (via Link)another player, same persona player — one stable id, never reused linklink: anonymous → registered, one waymerge: terminal; its id keeps resolving
Прив’язка — це трійка провайдер · суб’єкт · гравець. Вона переводить гостя в зареєстровані лише в один бік, а після об’єднання старий id і далі веде до гравця

Гравець — це носій облікових записів, а не рядок у вашій схемі, а його ідентифікатор стабільний, і його ніколи не видають повторно — навіть після об’єднання: id об’єднаного гравця й далі веде до гравця, а не перетворюється на висяче посилання. Прив’язка — це трійка: провайдер · зовнішній суб’єкт · гравець.

ЗавждиЩо це
провайдер + суб’єктунікальна пара, і ця унікальність породжує конфлікт, а не заборону: якщо акаунт уже зайнятий, вихід — обрати об’єднання
щонайбільше одна прив’язка на провайдера в гравцядругий акаунт того самого провайдера — конфлікт
зовнішній суб’єктніколи не стає ідентифікатором гравця. Він належить провайдерові, і якби ми взяли його за свій, наші id залежали б від чужих
тип облікового запису й статус доступу— різні осі. anonymous чи registered — одна, active / suspended / banned — інша, тож можна описати і «забаненого аноніма», і «тимчасово заблокованого зареєстрованого»
сесія й облікові дані— різні речі. Сесія — це запис, а облікові дані (credential) — те, що ви пред’являєте. Коли сесію відкликають, усі її облікові дані стають недійсними, а її відкриті підписки (subscription) закриваються
кілька одночасних сесійкожну можна відкликати окремо
твердження в облікових даних— оголошений контекст (регіон, локаль) і лише контекст. Твердження (claim) ніколи не дає повноважень
відбиток пристрою— не обліковий запис. Він ніколи не буде підставою впустити, лише підставою відмовити. Платформа зберігає й порівнює його тільки в незворотному вигляді

Три машини станів.

МашинаСтани
тип облікового записуanonymous → registered, і перехід односторонній
статус доступуactive ⇄ suspended, а коли бан знімають — active → banned → active
гравецьalive → merged, причому merged — кінцевий стан: об’єднаний гравець більше не входить

Що оголошуєте ви.

ОголошенняЩо це
політика входучи дозволено анонімний вхід, а також решта правил входу. Її оголошують атрибутом на точці монтування (mount point) модуля — не конфігом поруч із кодом і не під час виконання
роль за замовчуваннямнабір ролей (role), з яким новий гравець приходить під час першого входу. Для ролі за замовчуванням немає значення за замовчуванням: якщо нічого не оголосити, нові гравці прийдуть без ролей, і це повноцінне оголошення, а не пропуск
політика сесійщо робити, коли досягнуто стелі одночасних сесій: витіснити найстарішу й надіслати подію або відмовити новій. Значення за замовчуванням немає
політика видаленняяк видалення гравця доходить до даних, що на нього посилаються

Де налаштовують провайдера. На операторському рівні, а не в коді: обліковим даним магазину не місце в репозиторії. Те, що оголошено, видно в адмін-консолі лише для перегляду.

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

ЗавждиЩо це
це не самопризначеннящоб видати роль, потрібен оголошений для цього атомарний дозвіл (permission atom). Актор без нього отримає звичайний forbidden, а не мовчазну відсутність дії
видача ідемпотентнавидати роль, яку гравець уже має, — успіх, а не конфлікт. Стан — це набір ролей, а не історія викликів, тож, на відміну від входу, цій операції не потрібен ключ ідемпотентності
зміна ролей не миттєвавона набирає чинності без перевипуску облікових даних і стає помітною не пізніше за оголошену межу застарівання кешу прав. Якщо код видає роль і одразу перевіряє її на підключеному клієнті, це вікно треба враховувати

З чого складаються ролі й що вони відкривають, описано на сторінці Access & Roles.

Помилки

  • Облікових даних немає або вони прострочені — відповідь not authenticated, і це виправляє оновлення. Відкликані облікові дані дають ту саму відповідь, але оновлення тут не допоможе — лише новий вхід.
  • Облікові дані, які вже замінили під час ротації, пред’явили знову — це конфлікт. Саме завдяки цьому ротацію помічають, а не мовчки пропускають.
  • Забанений або тимчасово заблокований гравець, а також забанений відбиток отримують forbidden, і повторювати спробу марно.
  • Пара провайдер+суб’єкт зайнята — конфлікт; спробу можна повторити, коли оберете об’єднання. Другий акаунт того самого провайдера — конфлікт, який повтор не змінить.
  • Спроба відв’язати останній спосіб входу — відмова валідації: після неї до акаунта ніхто не зможе дістатися.
  • Об’єднати вже об’єднаного гравця не можна — це конфлікт, бо merged — кінцевий стан.
  • Коли провайдер недоступний, відповідь — unavailable, і спробу варто повторювати зі зростаючою паузою (backoff). Коли провайдер відхиляє облікові дані, відповідь — not authenticated, і тут вистачить однієї повторної спроби, а не циклу.
  • Перевищено частоту спроб входу — відповідь із категорії rate limit і час, після якого можна спробувати знову.

Обмеження

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

  • Одночасні сесії на гравця: залежно від оголошеної політики — витіснення найстарішої з подією або відмова новій. Значення за замовчуванням немає.
  • Спроби входу за період і спроби прив’язати зайняту пару: обмеження частоти з часом, після якого можна повторити, а лічильник спроб лишається в історії.
  • Прив’язки на гравця: прив’язку ще одного провайдера платформа відхиляє як конфлікт.
  • Строк дії облікових даних: not authenticated, повторити можна після оновлення. Строк дії облікових даних для оновлення: лише новий вхід.
  • Зберігання (retention) анонімного гравця без жодного входу: видалення за оголошеною політикою, з подією. Політику оголошують явно, значення за замовчуванням немає.
  • Записи в бан-списку відбитків: нове додавання платформа відхиляє, а старі записи ніколи не витісняє мовчки.