Цю сторінку ще не перекладено — показано англійську версію.
Таблиця лідерів у Tanks
У Tanks — навчальній арені зі сторінки Перші кроки — поки немає таблиці лідерів (leaderboard). У ц ьому уроці ми додамо щотижневу таблицю фрагів. Кроків три: оголосити таблицю, надсилати в неї фраги з хука і читати її на клієнті. Кожен крок посилається на сторінку модуля, якому належить те, чим ви на цьому кроці користуєтеся.
Оголосіть таблицю
Таблиця — це оголошення (declaration). Воно визначає, за яким полем (field) будують рейтинг, як поєднуються повторні надсилання, коли таблицю скидають і хто може в неї надсилати. Aggregation.Increment додає кожне надсилання до поточної суми, тож один фраг — одне очко. Submit.ServerOnly — типове значення: воно закриває таблицю для клієнтів, тому потрапити в неї можна лише так, як на кроці 2.
tanks-weekly-kills — фраги за спаданням, очки підсумовуються, скидання щопонеділка, надсилає лише сервер[Leaderboard("tanks-weekly-kills")]
public static class WeeklyKills
{
public static Owner Owner = Owner.Player;
public static Aggregation Agg = Aggregation.Increment;
public static Reset Reset = Reset.Weekly(DayOfWeek.Monday);
public static Submit Submit = Submit.ServerOnly;
[Rank(1, Sort.Descending)] public static int Kills;
}@Leaderboard('tanks-weekly-kills')
export class WeeklyKills {
static owner = Owner.Player;
static agg = Aggregation.Increment;
static reset = Reset.weekly(DayOfWeek.Monday);
static submit = Submit.ServerOnly;
@rank(1, Sort.Descending) static kills: number;
}@leaderboard("tanks-weekly-kills")
class WeeklyKills:
owner = Owner.PLAYER
agg = Aggregation.INCREMENT
reset = Reset.weekly(DayOfWeek.MONDAY)
submit = Submit.SERVER_ONLY
kills: int = rank(1, Sort.DESCENDING)Як оголошувати через атрибути в Go, поки не вирішено (O-1). Приклади з’являться, коли оберуть спосіб запису.
USTRUCT(PSLeaderboard = (Name = "tanks-weekly-kills", Owner = "Player", Aggregation = "Increment",
Reset = "Weekly:Monday", Submit = "ServerOnly"))
struct FWeeklyKills
{
GENERATED_BODY()
UPROPERTY(PSRank = (Order = 1, Sort = "Descending")) int32 Kills;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI[Leaderboard("tanks-weekly-kills")]
public static class WeeklyKills
{
public static Owner Owner = Owner.Player;
public static Aggregation Agg = Aggregation.Increment;
public static Reset Reset = Reset.Weekly(DayOfWeek.Monday);
public static Submit Submit = Submit.ServerOnly;
[Rank(1, Sort.Descending)] public static int Kills;
}Завантажте оголошення командою playserv push — і в панелі з’явиться порожня таблиця, для якої вже заплановано цикл зі скиданням у понеділок. Осі, яких ви не задали, лишаються з типовими значеннями. Повний перелік осей — власник, ключ сортування, поля для показу, правила турніру — є на сторінці Leaderboards.
Розклад — за UTC
Щотижневе скидання відбувається в понеділок о 00:00 UTC, а не за часовим поясом гравців.
Надсилайте фраги з хука
У Tanks життя танка вже завершує поріг HP, оголошений на самому танку: коли HP падає до нуля, спрацьовує перехід death, а одразу після нього платформа викликає хук. Хук — це хмарна функція з типізованими входом і в иходом, тож щоб надіслати фраг, у ній достатньо одного рядка.
[After] на вичерпання hp зараховує один фраг тому, хто знищив танк[After(Stats.Depleted, stat: "hp")]
public static Task SubmitKill(StatEvent e) =>
PlayServ.Leaderboards.Submit("tanks-weekly-kills", e.By.PlayerId,
kills: 1, idempotencyKey: e.Id);export const submitKill = after(Stats.depleted, { stat: 'hp' }, (e: StatEvent) =>
PlayServ.leaderboards.submit('tanks-weekly-kills', e.by.playerId,
{ kills: 1, idempotencyKey: e.id }));@after(stats.depleted, stat="hp")
async def submit_kill(e: StatEvent):
await playserv.leaderboards.submit("tanks-weekly-kills", e.by.player_id,
kills=1, idempotency_key=e.id)Як оголошувати через атрибути в Go, поки не вирішено (O-1). Приклади з’являться, коли оберуть спосіб запису.
Хук — це хмарна функція: він працює на платформі, а не в рушії. Напишіть його на C#, TypeScript або Python, а ваш код на Unreal підпишеться на подію rank changed, яку він породжує. У планах — функції, написані в самому рушії: графи Blueprint і C++ (його транслюватимуть у скрипт, який перевіряє платформа). Їх аналізуватимуть і завантажуватимуть, як будь-яке оголошення, а виконувати їх і далі буде платформа.
Хук — це хмарна функція: він працює на платформі, а не в рушії. Напишіть його на C#, TypeScript або Python, а ваш код на Unity підпишеться на подію rank changed, яку він породжує.
e.By — нападник, якого шкода вже несе в собі, тож окремо відстежувати, хто в кого стріляв, не потрібно. e.Id — ідентифікатор самої події (event), і таблиці з Increment потрібен саме він як ключ ідемпотентності: якщо подію про фраг доставлять повторно, її зарахують один раз, а не двічі. Точки виклику хуків, гарантії порядку і правила вето описано на сторінці Extensibility. Поріг, за яким спрацьовує хук, — це пресет характеристики (stat) на танку, а рядок із рахунком, який записує хук, — звичайні дані, до яких можна робити запити.
Читайте таблицю на клієнті
Для всього інтерфейсу вистачає двох запитів: верхівка таблиці та вікно навколо локального гравця (player) — п’ять рядків вище, п’ять нижче і ваш власний. Обидва повертають записи з позицією, кількістю фрагів та ім’ям для показу, і їх можна одраз у прив’язати до списку. Підписка (subscription) оновлює таблицю на екрані, поки триває матч, але надсилає лише позицію локального гравця.
var top = await playserv.Leaderboards.Top("tanks-weekly-kills", 20);
var around = await playserv.Leaderboards.AroundMe("tanks-weekly-kills", 5);
playserv.Leaderboards.OnRankChanged("tanks-weekly-kills", r => UpdateHud(r));const top = await playserv.leaderboards.top('tanks-weekly-kills', 20);
const around = await playserv.leaderboards.aroundMe('tanks-weekly-kills', 5);
playserv.leaderboards.onRankChanged('tanks-weekly-kills', (r) => updateHud(r));top = await playserv.leaderboards.top("tanks-weekly-kills", 20)
around = await playserv.leaderboards.around_me("tanks-weekly-kills", 5)
playserv.leaderboards.on_rank_changed("tanks-weekly-kills", lambda r: update_hud(r))Як оголошувати через атрибути в Go, поки не вирішено (O-1). Приклади з’являться, коли оберуть спосіб запису.
Client->Leaderboards->Of<FWeeklyKills>()->Get(
TPSOnResult<FPSBoard*>::CreateWeakLambda(this, [this](const TPSResult<FPSBoard*>& Result)
{
if (!Result.HasValue()) { return; }
OnBoard(Result.Value());
}));
// in OnBoard(FPSBoard* Board):
Board->Entries->Select().Page(20).Then(
TPSOnResult<TPSPage<FPSLeaderboardEntry>>::CreateWeakLambda(this, [this](const TPSResult<TPSPage<FPSLeaderboardEntry>>& Top)
{
if (!Top.HasValue()) { return; }
Hud->ShowTop(Top.Value().Rows);
}));
Board->Entries->SelectAround(MyPlayerId, /*Radius*/ 5,
TPSOnResult<TArray<FPSLeaderboardEntry>>::CreateWeakLambda(this, [this](const TPSResult<TArray<FPSLeaderboardEntry>>& Around)
{
if (!Around.HasValue()) { return; }
Hud->ShowWindow(Around.Value());
}));
TPSSubscription MyRank = Board->Subscribe->Mine(
[this](const FPSLeaderboardEntry& Mine) { UpdateHud(Mine); });
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.var top = await playserv.Leaderboards.Top("tanks-weekly-kills", 20);
var around = await playserv.Leaderboards.AroundMe("tanks-weekly-kills", 5);
playserv.Leaderboards.OnRankChanged("tanks-weekly-kills", r => UpdateHud(r));Понеділкове скидання закриває цикл, а не видаляє його, тож таблицю минулого тижня можна прочитати за її міткою — тим самим викликом Top з аргументом cycle:. Природний четвертий крок — хук, що видає нагороди, коли цикл закривається. Його описано на сторінці Leaderboards.
Що далі
- Leaderboards — осі, цикли, турніри і хук перед надсиланням, що обмежує підозрілі результати.
- Extensibility — усі точки виклику хуків по порядку і правила вето.
- Entity Presets — поріг характеристики, що на кроці 2 зарахував фраг.
- Аптечки в Tanks — другий приклад на Tanks: два оголошення й один хук.
- Перші кроки — арена Tanks, яку розширює цей урок.
- Основні поняття — словник, на який спирається кожна сторінка модуля.