Integrate with flexible pricing bundle
Overview
The AccelByte Gaming Services (AGS) flexible pricing bundle allows you to provide more reasonable pricing for player who already owned some items in the bundle and more consistent discounting experience as pricing will be in-sync when contents of a bundle go on sale
As demonstrated below, the final bundle price are calculated by the following factors: whether owned an item, item has a discount and bundle has a discount.
Integrate with Game Client
Login
Login to AGS, so that you have access to call other endpoints
- AGS OSS for Unreal Engine
- Unreal Engine SDK
IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get(ACCELBYTE_SUBSYSTEM);
FOnlineIdentityAccelBytePtr IdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(OnlineSubsystem->GetIdentityInterface());
if (!IdentityInterface.IsValid())
{
return;
}
const int32 LocalUserNum = 0;
auto AccelByteLoginCompletehandle = IdentityInterface->AddAccelByteOnLoginCompleteDelegate_Handle(LocalUserNum
, FAccelByteOnLoginCompleteDelegate::CreateLambda(
[this]
(int32 LoggedInLocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId,
const FOnlineErrorAccelByte& Error)
{
UE_LOG(LogTemp, Log, TEXT("Get AccelByteOnLoginComplete: LocalUserNum=%d"), LoggedInLocalUserNum);
})
);
const EAccelByteLoginType Type = EAccelByteLoginType::AccelByte;
const FString ID = TEXT("username");
const FString Password = TEXT("password");
IdentityInterface->Login(LocalUserNum, FOnlineAccelByteAccountCredentials{ Type , ID, Password });
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
const FString Username = TEXT("username");
const FString Password = TEXT("password");
ApiClient->User.LoginWithUsernameV3(Username, Password, FVoidHandler::CreateLambda([&]()
{
UE_LOG(LogTemp, Log, TEXT(" Success"));
bDeviceLoginSuccessful = true;
}), FOAuthErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage, const FErrorOAuthInfo& ErrorObject)
{
UE_LOG(LogTemp, Error, TEXT(" Error. Code: %d, Reason: %s"), ErrorCode, *ErrorMessage);
});
Get Flexible Pricing Bundle
To get flexible pricing bundles, make sure you have already created them in Admin Portal. You can check the boolean field "Flexible" from the response to determine whether it is a flexible pricing bundle
- AGS OSS for Unreal Engine
- Unreal Engine SDK
const FOnlineStoreV2AccelBytePtr OnlineStoreV2AccelByte = StaticCastSharedPtr<FOnlineStoreV2AccelByte>(StoreInterface);
const FOnlinePurchaseAccelBytePtr OnlinePurchaseAccelByte = StaticCastSharedPtr<FOnlinePurchaseAccelByte>(PurchaseInterface);
// GetItemsByCriteria to get flexible bundle item
FAccelByteModelsItemPagingSlicedResult ItemPagingSlicedResult{};
OnlineStoreV2AccelByte->AddOnGetItemsByCriteriaCompleteDelegate_Handle(FOnGetItemsByCriteriaCompleteDelegate::CreateLambda(
[this, &ItemPagingSlicedResult]
(bool bWasSuccessful, const FAccelByteModelsItemPagingSlicedResult& Value, const FOnlineError& Error) {
if (bWasSuccessful)
{
ItemPagingSlicedResult = Value;
}
}));
const FString Region = TEXT("US");
FAccelByteModelsItemCriteria ItemCriteria;
ItemCriteria.Language = TEXT("en");
ItemCriteria.Region = Region;
ItemCriteria.ItemType = EAccelByteItemType::BUNDLE;
ItemCriteria.CategoryPath = ECommerceTestFlexibleBundleItemCategoryPath;
auto UserId = IdentityInterface->GetUniquePlayerId(LocalUserNum).Get();
OnlineStoreV2AccelByte->GetItemsByCriteria(*UserId, ItemCriteria);
FString ItemId = ItemPagingSlicedResult.Data[0].ItemId;
FAccelByteModelsItemInfo Item;
FAccelByteModelsItemCriteria ItemCriteria;
ItemCriteria.Language = TEXT("en");
ItemCriteria.Region = Region;
ItemCriteria.ItemType = EAccelByteItemType::BUNDLE;
ItemCriteria.CategoryPath = TEXT("/flexibleBundle");
UE_LOG(LogTemp, Log, TEXT("GetItemsByCriteria"));
ApiClient->Item.GetItemsByCriteria(ItemCriteria, 0, 20, THandler<FAccelByteModelsItemPagingSlicedResult>::CreateLambda([&]
(const FAccelByteModelsItemPagingSlicedResult& Result)
{
UE_LOG(LogTemp, Log, TEXT(" ChildFound: %d"), Result.Data.Num());
for (int i = 0; i < Result.Data.Num(); i++)
{
if (Result.Data[i].Flexible)
{
UE_LOG(LogTemp, Log, TEXT(" Found"));
Item = Result.Data[i];
break;
}
}
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error. Code: %d, Reason: %s"), ErrorCode, *ErrorMessage)
});
Get Estimated Price
As the price can be varied by who and when to buy a flexible pricing bundle, game client need to call this endpoint to get the latest pricing for players
- AGS OSS for Unreal Engine
- Unreal Engine SDK
// GetEstimatedPrice to get the proper price when creating order
bool bGettingEstimatedPriceDone = false;
bool bGettingEstimatedPriceSuccess = false;
TArray<FAccelByteModelsEstimatedPrices> EstimatedPrices{};
OnlineStoreV2AccelByte->AddOnGetEstimatedPriceCompleteDelegate_Handle(FOnGetEstimatedPriceCompleteDelegate::CreateLambda(
[this, &EstimatedPrices]
(bool bWasSuccessful, const TArray<FAccelByteModelsEstimatedPrices>& Value, const FOnlineErrorAccelByte& Error) {
if (bWasSuccessful)
{
EstimatedPrices = Value;
}
}));
auto UserId = IdentityInterface->GetUniquePlayerId(LocalUserNum).Get();
OnlineStoreV2AccelByte->GetEstimatedPrice(*UserId, {ItemId}, Region);
TArray<FAccelByteModelsEstimatedPrices> EstimatedItems{};
UE_LOG(LogTemp, Log, TEXT("GetItemsByCriteria"));
ApiClient->Item.GetEstimatedPrice({ItemId}, Region,
THandler<TArray<FAccelByteModelsEstimatedPrices>>::CreateLambda([&EstimatedItems]
(const TArray<FAccelByteModelsEstimatedPrices>& Result)
{
EstimatedItems = Result;
})
, FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error. Code: %d, Reason: %s"), ErrorCode, *ErrorMessage)
});
Create Order
This is similar to normal create order flow, but make sure estimated price is used when placing an order for flexible pricing bundle
- AGS OSS for Unreal Engine
- Unreal Engine SDK
// Create Order to enabling OrderBundleItemInfos
const FString CurrencyCode = EstimatedPrices[0].EstimatedPrices[0].CurrencyCode;
const int32 DiscountedPrice = EstimatedPrices[0].EstimatedPrices[0].DiscountedPrice;
const int32 Price = EstimatedPrices[0].EstimatedPrices[0].Price;
FString OrderNo{};
constexpr int32 Quantity = 1;
FAccelByteModelsOrderCreate OrderCreate;
OrderCreate.CurrencyCode = CurrencyCode;
OrderCreate.DiscountedPrice = DiscountedPrice * Quantity;
OrderCreate.Price = Price * Quantity;
OrderCreate.Quantity = Quantity;
OrderCreate.ReturnUrl = TEXT("https://sdk.example.com");
OrderCreate.ItemId = ItemId;
OrderCreate.Region = Region;
OrderCreate.Language = TEXT("en");
bool bCreatingOrderDone = false;
bool bCreatingOrderSuccess = false;
FAccelByteModelsOrderInfo OrderInfo{};
OnlinePurchaseAccelByte->AddOnCreateNewOrderCompleteDelegate_Handle(FOnCreateNewOrderCompleteDelegate::CreateLambda(
[this, &OrderInfo]
(bool bWasSuccessful, FAccelByteModelsOrderInfo Value, const FOnlineErrorAccelByte& Error) {
if (bWasSuccessful)
{
OrderInfo = Value;
}
}));
auto UserId = IdentityInterface->GetUniquePlayerId(LocalUserNum).Get();
OnlinePurchaseAccelByte->CreateNewOrder(*UserId, OrderCreate);
FString OrderNo{};
constexpr int32 Quantity = 1;
FAccelByteModelsOrderCreate OrderCreate;
OrderCreate.CurrencyCode = EstimatedItems[0].EstimatedPrices[0].CurrencyCode;
OrderCreate.DiscountedPrice = EstimatedItems[0].EstimatedPrices[0].DiscountedPrice * Quantity;
OrderCreate.Price = EstimatedItems[0].EstimatedPrices[0].Price * Quantity;
OrderCreate.Quantity = 1;
OrderCreate.ReturnUrl = TEXT("https://sdk.example.com");
OrderCreate.ItemId = Item.ItemId;
OrderCreate.Region = TEXT("US");
OrderCreate.Language = TEXT("en");
UE_LOG(LogTemp, Log, TEXT("CreateNewOrder"));
ApiClient->Order.CreateNewOrder(OrderCreate
, THandler<FAccelByteModelsOrderInfo>::CreateLambda(
[&](const FAccelByteModelsOrderInfo& Result)
{
UE_LOG(LogTemp, Log, TEXT(" Success"));
OrderNo = Result.OrderNo;
})
, FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error. Code: %d, Reason: %s"), ErrorCode, *ErrorMessage)
});
Query Order
- AGS OSS for Unreal Engine
- Unreal Engine SDK
Query order details for flexible pricing bundle
// QueryUserOrders to check OrderBundleItemInfos exist
bool bGettingUserOrdersDone = false;
bool bGettingUserOrdersSuccess = false;
FAccelByteModelsPagedOrderInfo PagedOrderInfo{};
OnlinePurchaseAccelByte->AddOnQueryUserOrdersCompleteDelegate_Handle(FOnQueryUserOrdersCompleteDelegate::CreateLambda(
[this, &PagedOrderInfo]
(bool bWasSuccessful, const FAccelByteModelsPagedOrderInfo& Value, const FOnlineErrorAccelByte& Error) {
if (bWasSuccessful)
{
PagedOrderInfo = Value;
}
}));
FAccelByteModelsUserOrdersRequest UserOrdersRequest{};
UserOrdersRequest.ItemId = ItemId;
auto UserId = IdentityInterface->GetUniquePlayerId(LocalUserNum).Get();
OnlinePurchaseAccelByte->QueryUserOrders(*UserId, UserOrdersRequest);
The related information can be found in OrderBundleItemInfos variable
auto BundleInfo = PagedOrderInfo.Data[0].OrderBundleItemInfos;
UE_LOG(LogTemp, Log, TEXT("GetUserOrder"));
FAccelByteModelsOrderInfo OrderInfo{};
ApiClient->Order.GetUserOrder(OrderNo
, THandler<FAccelByteModelsOrderInfo>::CreateLambda(
[&](const FAccelByteModelsOrderInfo& Result)
{
UE_LOG(LogTemp, Log, TEXT(" Success"));
OrderInfo = Result;
})
, FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Error. Code: %d, Reason: %s"), ErrorCode, *ErrorMessage)
});
The related information can be found in OrderBundleItemInfos variable
auto BundleInfo = OrderInfo.OrderBundleItemInfos;