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

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

Bots

Бот заходить як звичайний гравець. Лише його мозок живе деінде. Та сама сесія, та сама перевірка на вході, ті самі правила, той самий ACL. Кімната навмисно не бачить різниці, тож боти грають за справжніми правилами вашої гри, а античиту ніколи не потрібні винятки для ботів.

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

  • Лобі треба заповнювати в години низького онлайну: FillRoom добирає матчі до квоти, а коли приходять люди, боти поступаються їм місцями (seat).
  • Боти мають грати за справжніми правилами (перевірка на вході, ACL, видимість), щоб античиту ніколи не знадобилися винятки для ботів.
  • У вас є власний зовнішній мозок (brain) — скажімо, навчена модель чи окремий сервіс, — і він підключається через ConnectAsBot, як будь-який гравець.
  • Сутність (entity) гравця, що відключився, має перейти до бота, а після перепідключення повернутися назад, і ні місце, ні передбачення цього не помітять.
  • Не потрібен, якщо персонаж нічого не вирішує. Діалоговий NPC без мозку належить до об’єктів світу.

Ця сторінка про те, як підключити бота: завести його в кімнату, добрати лобі до квоти, передати місце між ботом і людиною. Як написати мозок, який ухвалює рішення, розповідає сторінка Як написати мозок бота.

Хто що робить

АкторЩо робить на цій сторінці
bot-brainпідключається як гравець (player); отримує сприйняття; надсилає команди
room-ownerоголошує профілі, добирає кімнати (room) до квоти, передає місце між ботом і людиною

Коротко

Профіль filler: параметри складності, utility-мозок і FillRoom до квоти
[BotProfile("filler")]
[Brain(Kind.Utility)]
public static class Filler
{
    public static Difficulty Difficulty = Difficulty.Of(reactionMs: 250, aimJitter: 0.08f);

    [Consider(Targeting.NearestEnemy)] public static Behaviour Target;
    [Steer(Steering.SeekAndStrafe)]    public static Behaviour Move;
    [UseAbilities(When.Ready)]         public static Behaviour Fire;
}

PlayServ.Bots.FillRoom("battle", toQuota: 8, profile: "filler", minHumans: 1);
@BotProfile('filler')
@Brain({ kind: 'utility' })
export class Filler {
  static difficulty = Difficulty.of({ reactionMs: 250, aimJitter: 0.08 });

  @Consider(Targeting.nearestEnemy) target: Behaviour;
  @Steer(Steering.seekAndStrafe) move: Behaviour;
  @UseAbilities(When.ready) fire: Behaviour;
}

PlayServ.bots.fillRoom('battle', { toQuota: 8, profile: 'filler', minHumans: 1 });
@bot_profile("filler")
@brain(kind="utility")
class Filler:
    difficulty = Difficulty.of(reaction_ms=250, aim_jitter=0.08)

    target = consider(Targeting.NEAREST_ENEMY)
    move = steer(Steering.SEEK_AND_STRAFE)
    fire = use_abilities(When.READY)

playserv.bots.fill_room("battle", to_quota=8, profile="filler", min_humans=1)
Незабаром — Go

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

USTRUCT(PSBotProfile = "filler", PSBrain = (Kind = "Utility"))
struct FFiller
{
    GENERATED_BODY()

    UPROPERTY(PSDifficulty = (ReactionMs = 250, AimJitter = "0.08"))
    FPSDifficulty Difficulty;

    UPROPERTY(PSConsider = (Targeting = "NearestEnemy")) FPSBehaviour Target;
    UPROPERTY(PSSteer    = (Steering = "SeekAndStrafe")) FPSBehaviour Move;
    UPROPERTY(PSUseAbilities = (When = "Ready"))         FPSBehaviour Fire;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI

// a host tops up the room it serves
Client->Bots->FillRoom(PSKeys::Rooms::Battle,
    FPSFillRoomParams{ .ToQuota = 8, .Profile = TEXT("filler"), .MinHumans = 1 });
// 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; FillRoom потребує прав хоста, а вони є у збірки майстер-клієнта
[BotProfile("filler")]
[Brain(Kind.Utility)]
public static class Filler
{
    public static Difficulty Difficulty = Difficulty.Of(reactionMs: 250, aimJitter: 0.08f);

    [Consider(Targeting.NearestEnemy)] public static Behaviour Target;
    [Steer(Steering.SeekAndStrafe)]    public static Behaviour Move;
    [UseAbilities(When.Ready)]         public static Behaviour Fire;
}

PlayServ.Bots.FillRoom("battle", toQuota: 8, profile: "filler", minHumans: 1);

Зовнішній мозок (важчий ШІ, навчена модель, окремий сервіс) підключається, як будь-який гравець:

ConnectAsBot підключає зовнішній мозок як гравця: на вході ті самі дельти, на виході те саме введення
var bot = await PlayServ.ConnectAsBot(projectKey, botId: "trainer-07");
var seat = await bot.Matchmaking.Find("battle");
var room = await bot.Rooms.Join(seat);
// perception in ← the same deltas a player receives; commands out ← the same inputs
const bot = await PlayServ.connectAsBot(projectKey, { botId: 'trainer-07' });
const seat = await bot.matchmaking.find('battle');
const room = await bot.rooms.join(seat);
// perception in ← the same deltas a player receives; commands out ← the same inputs
bot = await PlayServ.connect_as_bot(project_key, bot_id="trainer-07")
seat = await bot.matchmaking.find("battle")
room = await bot.rooms.join(seat)
# perception in ← the same deltas a player receives; commands out ← the same inputs
Незабаром — Go

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

// An Unreal-based trainer client is a legitimate brain — it connects as a player.
FPlayServClient::ConnectAsBot(ProjectKey, TEXT("trainer-07"),
    TPSOnResult<FPlayServClient*>::CreateLambda([](const TPSResult<FPlayServClient*>& Result)
    {
        if (!Result.HasValue()) { return; }
        FPlayServClient* Bot = Result.Value();
        Bot->Matchmaking->Of<FBattleQueue>()->Tickets->Create(FPSTicketClaim{ .Mode = TEXT("battle") },
            TPSOnResult<FPSTicket*>::CreateLambda([Bot](const TPSResult<FPSTicket*>& TicketResult)
            {
                if (!TicketResult.HasValue()) { return; }
                TPSSubscription Placement = TicketResult.Value()->Subscribe(
                    [Bot](const FPSSeat& Seat) { Bot->Rooms->Join(Seat); });
            }));
    }));
// perception in ← the same deltas a player receives; commands out ← the same inputs
// 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 без змін зі згенерованими типами
var bot = await PlayServ.ConnectAsBot(projectKey, botId: "trainer-07");
var seat = await bot.Matchmaking.Find("battle");
var room = await bot.Rooms.Join(seat);
// perception in ← the same deltas a player receives; commands out ← the same inputs

Модель

Власних понять бот не вводить. Це облікові дані актора плюс те, що вже оголошено для кімнат, даних і переміщення.

Що містить оголошення бота.

Що оголошуєЩо це
тік мисленняяк часто опитують мозки. Це не тік симуляції: мозки працюють зовні, і мережевий виклик на кожному тіку неможливий
де працюють мозкиу хмарній функції, на бекенді студії чи на її ігровому сервері. Конкретне місце не входить у контракт, і переїзд між ними не ламає сумісності
пресет актораправа бота у вигляді звичайного пресета актора
видимість позначки ботачи повідомляють учасникам, що це бот. Сама позначка існує завжди, і платформа завжди її бачить. Чи бачать її гравці, оголошує тип кімнати: на одних ринках розкривати суперника-ШІ зобов’язує закон, на інших це продуктове рішення
поведінка, коли мозки недоступніодин із трьох варіантів, без значення за замовчуванням: do nothing · leave the room · fall back to built-in default behaviour
добір складуйого оголошує тип кімнати: скільки ботів, за якої умови й до якого моменту. Модуль Matchmaking нічого не знає про ботів: він підбирає акторів і не вирішує, ким добирати склад

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

ЗавждиЩо це
актор, а не гравецьу бота є облікові дані актора, але немає провайдера входу, прив’язаних акаунтів і сесій
економічне володіннявідсутнє: ні прав володіння, ні покупок, ні записів у таблицях лідерів (leaderboard)
сприйняттятаке саме, як у гравця: та сама зона видимості, той самий предикат, той самий ліміт кількості об’єктів. Бот і гравець в одній позиції отримують однаковий набір об’єктів, тож бачити крізь стіни бот може не більше, ніж гравець
ширше сприйняттяце властивість пресета актора, а не бота. Режим налагодження чи «всевидющого тренера» оголошують як пресет із ширшим предикатом
між рішеннямидіє остання команда, а що з нею буде далі, уже оголошено в типі руху для застарілого введення. Бот, чий мозок ще думає, — той самий випадок, що й гравець, у якого зникла мережа
місткість кімнативраховує бота: він займає місце нарівні з усіма

Помилки

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

Обмеження

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

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