Play
Dynamically assemble and match players
Dynamically assemble and match players
Connect cross-platform accounts & identity management
Grow and commercialize your game
Build a vibrant community
Track player progression and game state across platforms
Track, engage, and retain players
Visualize game metrics
Our latest product update in Monetization has some very exciting new features that we can’t wait to share with you: loot box functionality which can also be customized using our gRPC framework. Loot Box is introduced as a new item type and can be created and configured in our Store.
As usual, the customization capabilities will enable you to customize your loot box rewarding rules, so that you can design your own special rewarding mechanisms to attract more players’ interests. Read on to learn more.
AccelByte’s Loot Box is a new item type in our Store. Each loot box can contain a list of other items which each have their own probability of appearing when a loot box is opened. This can be used to grant players entitlements of one or more rewards from a predefined pool of rewards based on probabilities you set.
When you create a loot box, you will need to choose a list of items to create a pool of items so that when players open a loot box, they will be rewarded based on a random draw from that pool.
You can add items one by one and assign a probability to each individually, or you may also choose to add a group of items together and assign a probability to that entire group.
Creating an ‘Item Group’ is especially useful when you think a group of items have a similar rarity and thus each individual item within the group should share the same probability. For example, you can put items into groups like Common, Rare, and Ultra Rare, and assign each group a probability value. If 80% probability is assigned to Common group, that means there is an 80% chance that items from the Common group will be rewarded to a player when a loot box is opened.
If you want more than our default rewarding mechanism by simply setting probabilities, you may also use our ‘Custom Roll Function’ to start your customizations using our gRPC service. When the function is enabled, AccelByte will call the gRPC server to determine which rewards to be granted when players open loot boxes.
Here are just a few of the potential customization examples for your reference:
To achieve that, developers will only need to override a couple of gRPC methods in any language of their choice.
service LootBox {
rpc RollLootBoxRewards(RollLootBoxRewardsRequest) returns (RollLootBoxRewardsResponse);
}
The following is an example Java implementation that illustrates how players are guaranteed with an Ultra Rare Item after opening 10 loot boxes (sample code only).
@Slf4j
@GRpcService
public class LootboxServiceImplementation extends LootBoxGrpc.LootBoxImplBase {
// For reference only, please use persistent storage to store this record in real world application
private final Map<String, Integer> userRollCounts = new HashMap<>();
@Override
public void rollLootBoxRewards(RollLootBoxRewardsRequest request, StreamObserver<RollLootBoxRewardsResponse> responseObserver) {
log.info("Received rollLootBoxRewards request");
String userId = request.getUserId();
LootBoxItemInfo itemInfo = request.getItemInfo();
int numOfRewardsPerBox = itemInfo.getRewardCount();
int rollsRequested = request.getQuantity();
int totalWeight = 0;
List<LootBoxRewardWeight> lootBoxRewardWeightList = new ArrayList<>();
// accumulate rolling weight
for (LootBoxRewardObject lootBoxReward : itemInfo.getLootBoxRewardsList()) {
totalWeight += lootBoxReward.getWeight();
lootBoxRewardWeightList.add(new LootBoxRewardWeight(totalWeight, lootBoxReward.getItemsList(), LootBoxRewardType.valueOf(lootBoxReward.getType())));
}
List<RewardObject> rewards = new ArrayList<>();
int userRollCount = userRollCounts.getOrDefault(userId, 0);
// finding an Ultra Rare reward based on rewards names
LootBoxRewardObject ultraRareReward = itemInfo.getLootBoxRewardsList().stream().filter(lootBoxReward-> {lootboxReward.getName().equals("UltraRare")}).findFirst().orElseThrow(() -> new InternalException("Not Found"));
// roll rewards
for (int rollCount = 0; rollCount < rollsRequested; rollCount++) {
if (userRollCount > 0 && userRollCount % 10 == 0) {
// ultra rare item guaranteed
rewards.add(randomUltraRareItem(ultraRareReward));
} else {
// roll based on probability group or return all rewards
for (int rewardCount = 0; rewardCount < numOfRewardsPerBox; rewardCount++) {
List<RewardObject> entitlementLootBoxRewards = rollLootBoxReward(totalWeight, lootBoxRewardWeightList).stream().map(this::toRewardObject).collect(Collectors.toList());
rewards.addAll(entitlementLootBoxRewards);
}
}
++userRollCount;
}
userRollCounts.put(userId, userRollCount);
RollLootBoxRewardsResponse response = RollLootBoxRewardsResponse
.newBuilder()
.addAllRewards(rewards)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
private List<BoxItemObject> rollLootBoxReward(int totalWeight, List<LootBoxRewardWeight> lootBoxRewardWeights) {
int num = new Random().nextInt(totalWeight) + 1; // random a number from [1, totalWeight]
for (LootBoxRewardWeight lootBoxRewardWeight : lootBoxRewardWeights) {
if (num > lootBoxRewardWeight.finalWight) {
continue;
}
List<BoxItemObject> itemsList = lootBoxRewardWeight.lootBoxItems;
if (LootBoxRewardType.PROBABILITY_GROUP.equals(lootBoxRewardWeight.type)) {
int randomNum = new Random().nextInt(itemsList.size()); // random a number from [0, reward count)
return Collections.singletonList(itemsList.get(randomNum));
} else {
return itemsList;
}
}
throw new Error();
}
private RewardObject randomUltraRareItem(LootBoxRewardObject lootBoxRewardObject) {
List<BoxItemObject> ultraRareItemList = lootBoxRewardObject.getItemsList();
int randomNum = new Random().nextInt(ultraRareItemList.size());
BoxItemObject randomUltraRareBoxItem = ultraRareItemList.get(randomNum);
return RewardObject.newBuilder()
.setCount(randomUltraRareBoxItem.getCount())
.setItemId(randomUltraRareBoxItem.getItemId())
.setItemSku(randomUltraRareBoxItem.getItemSku()).build();
}
private RewardObject toRewardObject(BoxItemObject boxItemObject) {
return RewardObject.newBuilder()
.setCount(boxItemObject.getCount())
.setItemId(boxItemObject.getItemId())
.setItemSku(boxItemObject.getItemSku()).build();
}
}
Now you have one more method to leverage a direct relationship with your players by customizing how they interact with your in-game stores! With AccelByte, developers can own relationships throughout the player experience. Our commerce collection of services serves as the backbone for a publishing platform or in-game store, from product catalogs, purchases, and fulfillment to digital ownership.
Interested in learning more about our solutions? Request a demo here.
Reach out to the AccelByte team to learn more.