Устройство «Транзакции на острове» содержит уже готовый шаблон для транзакций на острове. В нем предусмотрены все необходимые возможности для ключевых аспектов работы модуля магазина в API Verse. Сюда входят предметы, предложения, предлагаемые наборы, а также обработка покупок через интерфейс стандартной витрины. С помощью этого кода вы можете быстро подготовить собственную витрину.
Для доступа к устройству:
перейдите в проводник Verse;
щёлкните правой кнопкой мыши по названию вашего проекта;
выберите «Добавить новый файл Verse в проект»;
выберите устройство «Транзакции на острове».
Создание предметов
Предметы определяются в коде Verse как позиции, и для них предусмотрены две категории: расходуемые предметы, которые удаляются из инвентаря игрока при использовании, а также предметы длительного пользования, которые не расходуются и не удаляются из инвентаря при использовании.
Модуль EntitlementInfo
Модули — это целостные единицы кода, которые можно перераспределять для использования в нескольких файлах. В модули можно вносить изменения в любое время, не нарушая зависимости в файле, в котором тот или иной модуль уже используется. Вы можете вынести длинные или повторяющиеся части кода, например определения позиций, в отдельный файл, а затем импортировать их с помощью оператора using.
Модуль EntitlementInfo собирает названия, полные и краткие описания всех позиций в шаблоне. Вы можете включить этот модуль в любой файл, в котором необходимо определить позиции, чтобы не переопределять название и другие переменные для одного и того же продукта, что упростит процесс изменения информации о позициях и уменьшит сложность их отладки.
# Setup your entitlements and offers data, in this case that's your Names, Descriptions & Short Descriptions as well as any other data you want to be constant
EntitlementInfo<public> := module:
Potion<public> := module:
Name<public><localizes>:message = "Potion"
Description<public><localizes>:message = "Adds +10 health when used. Green so you know its healthy!"
Определения позиций
Любая позиция в Verse имеет следующие свойства:
Name — название позиции (не более 50 символов);
Description — полное описание, отображаемое рядом с позицией (не более 500 символов);
ShortDescription — краткое описание позиции (не более 100 символов);
Icon — значок (изображение) позиции.
Если ваша позиция является случайным платным предметом, в её описании необходимо указать точную процентную вероятность её получения игроком. Подробнее см. в статье Случайные платные предметы.
Позиция в Verse также может иметь следующие дополнительные свойства:
MaxCount — максимальное количество таких позиций, которое может быть у игрока одновременно;
Consumable — если установлено значение true, позиция может быть использована с применением функции
ConsumeEntitlement, что уменьшает общее количество позиций для пользователя в системе Epic по мере их использования. Если установлено значение false, позиция является предметом длительного пользования и не будет уменьшаться по мере использования;PaidArea — если установлено значение true, позиция предоставляет доступ к платной области;
PaidRandomItem — если установлено значение true, позиция приобретается или получается вместе с контентом, купленным ради случайной награды;
ConsequentialToGameplay — если для этого поля установлено значение true, предмет даёт существенное преимущество на вашем острове. Подробнее см. в разделе Влияние на игровой процесс.
В приведённом ниже фрагменте кода используется ранее определённый модуль EntitlementInfo для создания определений ваших позиций. Чтобы задать определение расходуемой позиции, для параметра Consumable должно быть установлено значение true.
Прежде чем задать определение позиции, необходимо создать базовый класс позиции, который будет использоваться для позиций в вашем проекте,
— в данном случае function_example_entitlement.
Вы также должны указать путь к файлу текстуры значка для определения каждой позиции, в противном случае определение позиции не пройдёт проверку.
Entitlements<public> := module:
using {EntitlementInfo}
# The base entitlement you should define for ALL your entitlements in your experience
feature_example_entitlement<public> := class<abstract><castable>(entitlement){}
basic_sword<public> := class<concrete>(feature_example_entitlement):
var Name<override>:message = Sword.Name
По умолчанию предметы не являются расходуемыми и для MaxCount у них установлено значение 1. Если предмет является платной областью или случайным платным предметом, либо даёт существенное преимущество в игре, соответствующие поля должны быть определены в коде.
Предлагаемые позиции
Предложение подразумевает наличие у предмета или ресурса определённой цены (в В-баксах). У каждого предложения есть собственное название, описание и значок — отдельно от информации о позиции. Предложение определяется в коде Verse.
Чтобы продать позицию, вам необходимо создать соответствующее предложение.
У каждого предложения имеются следующие свойства:
Name — название предложения;
Description — полное описание, отображаемое рядом с предложением;
ShortDescription — краткое описание предложения в небольшом диалоговом окне;
Icon — значок (изображение) предложения;
EntitlementType — указание позиции, включённой в предложение;
Price — цена в В-баксах. Она должна находиться в диапазоне от 50 до 5000 В-баксов включительно и быть кратна 50.
В этом фрагменте кода демонстрируется, как задать определение предложения, используя существующий модуль EntitlementInfo для хранения базовой информации о предлагаемой позиции. Вам также нужно определить значок, EntitlementType,
который определяет предлагаемую позицию и цену в В-баксах. Вы также можете при необходимости включить в определение минимальный возраст для покупки предложения в зависимости от фиксированного значения или кода страны, либо ограничить доступ к предложению для семейства платформ, а также использовать комбинацию этих вариантов. Несколько примеров таких определений показаны во фрагменте кода ниже.
Коды регионов в настоящее время не поддерживаются и будут доступны в одном из следующих обновлений.
ExampleOffers<public> := module:
using {EntitlementInfo}
basic_sword<public> := class(entitlement_offer):
var Name<override>:message = EntitlementInfo.Sword.Name
var Description<override>:message = EntitlementInfo.Sword.Description
var ShortDescription<override>:message = EntitlementInfo.Sword.ShortDescription
Цена в В-баксах должна быть кратна 50 и находиться в диапазоне от 50 до 5000 В-баксов.
Для случайных платных предметов необходимо обеспечить игрокам возможность видеть точную процентную вероятность получения каждого случайного платного предмета в сведениях о предложении. Невыполнения этого требования будет являться нарушением Правил для разработчиков Fortnite, которое может повлечь за собой ограничительные меры в отношении вас и вашего острова.
Более подробная информация приведена в разделе Ограничения на транзакции на острове.
Предлагаемые наборы
Наборы определяются в коде Verse и могут содержать определённую комбинацию из различных предложений, наборы определённого количества одинаковых предложений или же и то, и другое. Как и в случае с простыми предложениями, предлагаемые наборы имеют собственную цену, название и описание, а также значок, отличающий их от других позиций и предложений. Вы также можете создавать вложенные предложения, поместив несколько наборов внутри одного такого предложения. Например, это может быть набор, доступный только в течение ограниченного времени, в который входят лопата и набор пакетов с семенами кукурузы. Такой подход позволяет создавать комбинированные наборы из более мелких наборов предложений.
Ниже представлены стандартные разновидности наборов.
Набор позиций одного типа — набор, содержащий несколько предложений одной и той же позиции, обычно по сниженной цене.
Набор из нескольких предложений — комбинированный набор, включающий предложения нескольких позиций, в том числе из наборов позиций одного типа и стандартных предложений.
Набор представляет собой массив кортежей, каждый из которых содержит заранее определённое предложение и целочисленное значение, которое определяет количество для такого предложения.
Для успешной транзакции количество вложенных уровней не должно превышать 5. Старайтесь по возможности ограничивать вложенность предложений.
В приведённом ниже фрагменте кода демонстрируется создание набора зелий. Информация о предложении определяется в модуле EntitlementInfo и включает в себя переменную PotionCount.
ExampleOffers<public> := module:
using {EntitlementInfo}
<# --- other offer definitions above --- #>
potion_pack<public> := class(bundle_offer) :
var Name<override>:message = EntitlementInfo.PotionPack.Name
Ограничения на покупку
Вы можете ограничить покупку позиций, чтобы можно было создавать праздничные предметы ограниченной серии, поощрительные или сезонные предложения, а также создавать контент для определённых регионов.
GetMinPurchaseAge
Используйте GetMinPurchaseAge, чтобы определить ограничение на покупку для конкретного entitlement_offer. Она вызывается автоматически при проверке покупки, поэтому требует лишь определения. Вы можете задать точное целочисленное значение, код страны или семейство платформ.
Коды регионов в настоящее время не поддерживаются и будут доступны в одном из следующих обновлений.
Ниже приведено несколько примеров функции GetMinPurchaseAge.
# Optional overrideable function you can use to inform Epic systems what the minimum age a player needs to be to purchase this offer
GetMinPurchaseAge<override>(CountryCode:string, SubdivisionCode:string, PlatformFamily:string)<decides><computes>:int =
# A Hypothetical example where you only want to sell swords to people who don't live in Antarctica
CountryCode <> CountryCodes.Antarctica
return 0
Проверка позиций игрока
Проверка позиций игрока — это необходимый шаг для сохранения приобретённых игроками позиций между сеансами. Отсутствие надлежащей проверки позиций может привести к таким проблемам, как дублирование или потеря позиции.
Проверка предыдущих покупок
В приведённом ниже фрагменте кода демонстрируется простая проверка позиции, которая выполняется при присоединении игрока к сеансу. Сначала проверяется, подписан ли данный игрок на событие OnPurchasesChanged. Затем, если игрок ещё не подписан, он будет подписан. Наконец, с помощью ValidatePreviousPurchases извлекается запись обо всех приобретённых позициях данного игрока.
На этом этапе рекомендуется также выполнять проверки позиций игроков, чтобы убедиться, что все сохранённые данные в игре соответствуют данным из API магазина и совпадают с инвентарём игрока.
OnPlayerJoin(InPlayer:player):void =
Subscription := GetEntitlementsChangedEvent(InPlayer, Entitlements.feature_example_entitlement).Subscribe(OnPurchasesChanged)
if (set EntitlementChangeSubscription[InPlayer] = option{Subscription}):
Print("Adding entitlement Change Subscription player subscription")
# On players joining you are likely going to want to run some validation checks to make sure that any data you save
Обработка покупок
Для обработки покупок позиций используются две основные функции — это BuyOffer и OnPurchasesChanged. Первая функция отвечает за логику представления игроку предложения и проверки покупки. Вторая функция обрабатывает логику успешной транзакции или возврата. Приведённые ниже фрагменты кода демонстрируют работу обеих функций.
# Base Implementation of how to present players with an offer to purchase in your experience
TryBuyOffer(Player:player, Offer:entitlement_offer)<suspends>:void =
Result := BuyOffer(Player, Offer)
if (Result?):
# do nothing it should respond in the purchase subscription, see OnPurchasesChanged for details
Обработка расходуемых предметов
Для расходования расходуемой позиции необходимо воспользоваться функцией ConsumeEntitlement из Verse API магазина. После успешного расходования необходимо обработать логику эффекта, генерируемого после расходования. Количество позиций (Count), принадлежащих игроку, будет уменьшено на израсходованное количество (Count), отслеживаемое функцией.
В приведённом ниже фрагменте кода демонстрируется, как определённая позиция расходуется определённым игроком.
# Base Implementation of how to flag a consumable in your experience as being consumed
TryConsumeEntitlement(Player:player, Entitlement:concrete_subtype(entitlement), NumberConsuming:int)<suspends>:void =
Result := ConsumeEntitlement(Player, Entitlement, ?Count := NumberConsuming)
if (Result?):
Print("Successfully consumed entitlement!")
Вы не можете расходовать позиции длительного пользования. Если вы попытаетесь сделать это, ConsumeEntitlement вернёт ошибку.
Выдача позиций
Помимо продажи позиций за В-баксы, вы можете предоставлять позиции игрокам с помощью метода GrantEntitlement.
Выдача позиций может использоваться для предоставления рекламных предметов, бесплатных образцов расходуемых предметов, а также для восстановления предметов в инвентаре, пропавших из-за ошибок или сбоев.
Во фрагменте кода ниже показан метод предоставления позиций вашим игрокам.
# Base Implementation of how to give players a entitlement in your experience without them purchasing it
TryGrantEntitlement(Player:player, Entitlement:concrete_subtype(entitlement), NumberToGrant:int)<suspends>:void =
Result := GrantEntitlement(Player, Entitlement, ?Count := NumberToGrant)
if (Result?):
Print("Successfully granted a player your entitlement!")
При попытке предоставить количество позиций, превышающее максимально допустимое (Max Count), или выдать более одного предмета длительного пользования позиции не будут выданы.
Демонстрация предлагаемых позиций игрокам
Модуль Marketplace module предоставляет встроенный интерфейс витрины, который можно использовать на ваших островах с помощью функции ShowOffersDialog. В приведённом ниже фрагменте кода демонстрируется способ отображения витрины с предложениями для определённого игрока.
# Base Implementation of how to show an array of offers to the player that are available for purchase
ShowArrayOfOffers(Player:player)<suspends>:void =
ShowOffersDialog(Player, array{ExampleOffers.basic_sword{}, ExampleOffers.potion{}, ExampleOffers.potion_pack{}, ExampleOffers.potion_thanksgiving{}, ExampleOffers.potion_gib{}})Полный код
using { /Fortnite.com/Devices }
using { /Fortnite.com/Marketplace }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Assets }
using { /Verse.org/Simulation }