ルートボックスロール関数入門
Last updated on February 4, 2026
注釈:本資料はAI技術を用いて翻訳されています。
概要
この記事では、ルートボックスロール用の Extend Override アプリで使用される API コントラクト(Protobuf)について説明します。
service LootBox {
rpc RollLootBoxRewards(RollLootBoxRewardsRequest) returns (RollLootBoxRewardsResponse);
}
API コントラクト
RollLootBoxRewards
RollLootBoxRewards は、プレイヤーがルートボックスを消費したときに AccelByte Gaming Services(AGS)によって呼び出され、指定されたプレイヤーに与えられたルートボックス報酬リストからどの報酬アイテムが与えられるかを決定するロジックを実装するために使用されます。
この例では、要求された数量分の報酬アイテム結果を生成しています。
まず、報酬の合計ウェイトに基づいてランダムに報酬を選択します。ウェイトが大きいほど、その報酬が選択される確率が高くなります。また、選択された報酬からランダムにアイテムを取得します。最後に、そのアイテムをレスポンスとして最終結果に追加します。
- C#
- Go
- Java
- Python
アプリ内では、以下の関数が src/AccelByte.PluginArch.LootBox.Demo.Server/Services/LootboxFunctionService.cs にあります。
public override Task<RollLootBoxRewardsResponse> RollLootBoxRewards(RollLootBoxRewardsRequest request, ServerCallContext context)
{
var rewards = request.ItemInfo.LootBoxRewards;
int rewardWeightSum = 0;
foreach (var reward in rewards)
rewardWeightSum += reward.Weight;
Random rand = new Random();
List<RewardObject> result = new List<RewardObject>();
for (int i = 0; i < request.Quantity; i++)
{
int selectedIdx = 0;
for (double r = rand.NextDouble() * rewardWeightSum; selectedIdx < rewards.Count - 1; selectedIdx++)
{
r -= rewards[selectedIdx].Weight;
if (r <= 0.0)
break;
}
var selectedReward = rewards[selectedIdx];
int itemCount = selectedReward.Items.Count;
int selectedItemIdx = (int)Math.Round(rand.NextDouble() * (double)(itemCount - 1));
BoxItemObject selectedItem = selectedReward.Items[selectedItemIdx];
var rewardObject = new RewardObject()
{
ItemId = selectedItem.ItemId,
ItemSku = selectedItem.ItemSku,
Count = selectedItem.Count
};
result.Add(rewardObject);
}
RollLootBoxRewardsResponse response = new RollLootBoxRewardsResponse();
response.Rewards.AddRange(result);
return Task.FromResult(response);
}
アプリ内では、以下の関数が pkg/service/lootbox_service.go にあります。
func (s *LootboxServiceServer) RollLootBoxRewards(_ context.Context, req *pb.RollLootBoxRewardsRequest) (*pb.RollLootBoxRewardsResponse, error) {
rewards := req.GetItemInfo().GetLootBoxRewards()
rewardWeightSum := 0
for _, r := range rewards {
rewardWeightSum += int(r.Weight)
}
var resultItems []*pb.RewardObject
for i := int32(0); i < req.GetQuantity(); i++ {
selectedIdx := 0
for r := int(random(rewardWeightSum)); selectedIdx < len(rewards); selectedIdx++ {
r -= int(rewards[selectedIdx].GetWeight())
if r <= 0.0 {
break
}
}
selectedReward := rewards[selectedIdx]
selectedRewardItemCount := len(selectedReward.GetItems())
selectedItemIdx := int(math.Round(random(selectedRewardItemCount - 1)))
selectedItem := selectedReward.GetItems()[selectedItemIdx]
resultItems = append(resultItems, &pb.RewardObject{
ItemId: selectedItem.ItemId,
ItemSku: selectedItem.ItemSku,
Count: selectedItem.Count,
})
}
response := &pb.RollLootBoxRewardsResponse{Rewards: resultItems}
return response, nil
}
アプリ内では、以下の関数が src/main/java/net/accelbyte/service/LootboxServiceImplementation.java にあります。
@Override
public void rollLootBoxRewards(RollLootBoxRewardsRequest request, StreamObserver<RollLootBoxRewardsResponse> responseObserver) {
List<RewardObject> finalItems = new ArrayList<>();
List<LootBoxItemInfo.LootBoxRewardObject> rewards = request.getItemInfo().getLootBoxRewardsList();
int rewardWeightSum = 0;
for (LootBoxItemInfo.LootBoxRewardObject reward: rewards) {
rewardWeightSum += reward.getWeight();
}
for (int i=0;i<request.getQuantity();i++)
{
int selIdx = 0;
for (double r = Math.random() * rewardWeightSum; selIdx < rewards.size() - 1; ++selIdx) {
r -= rewards.get(selIdx).getWeight();
if (r <= 0.0)
break;
}
LootBoxItemInfo.LootBoxRewardObject selReward = rewards.get(selIdx);
int itemCount = selReward.getItemsCount();
int selItemIdx = (int)Math.round(Math.random() * (itemCount - 1));
BoxItemObject selItem = selReward.getItems(selItemIdx);
RewardObject rewardItem = RewardObject
.newBuilder()
.setItemId(selItem.getItemId())
.setItemSku(selItem.getItemSku())
.setCount(selItem.getCount())
.build();
finalItems.add(rewardItem);
}
RollLootBoxRewardsResponse response = RollLootBoxRewardsResponse
.newBuilder()
.addAllRewards(finalItems)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
アプリ内では、以下の関数が src/app/services/lootbox_service.py にあります。
async def RollLootBoxRewards(self, request: RollLootBoxRewardsRequest, context):
self.log_payload(f'{self.RollLootBoxRewards.__name__} request: %s', request)
final_items: List[RewardObject] = []
rewards: List[LootBoxItemInfo.LootBoxRewardObject] = request.itemInfo.lootBoxRewards
reward_weight_sum: int = 0
reward_weight_sum = sum(reward.weight for reward in rewards)
for i in range(request.quantity):
for sel_idx in range(len(rewards)):
r = random.random() * reward_weight_sum
r -= rewards[sel_idx].weight
if r <= 0.0:
break
sel_reward: LootBoxItemInfo.LootBoxRewardObject = rewards[sel_idx]
item_count: int = len(sel_reward.items)
sel_item_idx: int = random.randint(0, item_count-1)
sel_item: BoxItemObject = sel_reward.items[sel_item_idx]
reward_item: RewardObject = RewardObject(
itemId=sel_item.itemId,
itemSku=sel_item.itemSku,
count=sel_item.count,
)
final_items.append(reward_item)
response: RollLootBoxRewardsResponse = RollLootBoxRewardsResponse(
rewards=final_items
)
self.log_payload(f'{self.RollLootBoxRewards.__name__} response: %s', response)
return response
備考
gRPC リクエスト処理の詳細については、こちらをご覧ください。