基本的なストア操作
通常、ゲーム内ストアには、次の 3 つの基本操作があります。
このドキュメントでは、各操作に関連するサンプル コードを示します。 これは、絶えず更新してベスト プラクティスを反映している InGameStore サンプルから抽出されています。
XStore API を呼び出す準備
すべての XStore
API は、XStoreCreateContext を使用して作成された XStoreContextHandle を対象として動作します。
このコンテキストでは、本体上の指定されたユーザーおよび PC 上で利用可能な 1 人のユーザーのコンテキストでストア操作を実行できます。 本体では、このコンテキストは、中止されたイベントまたはすぐ再開するイベントの後で無効になります。 このような条件に安全に対処するには、XStoreContextHandle を閉じて、一時停止状態から再開するたびに再作成することをお勧めします。
1. 購入できるアイテムを決める
通常、ゲームで購入できるものはアドオンです。 次のコードは、利用できる製品を確認するための、ゲームに必要な基本的な XStoreQueryAssociatedProductsAsync API 呼び出しを示しています。
このクエリでは、ゲームに関連付けられた購入可能なアドオンが自動的に返されます。 パートナー センターの商品の関連付け設定セクションで、ゲームがこの製品との「can sell」関係に設定されている場合、この製品に同じ発行元に関連付けられている無関係の製品 (同じパートナー センター アカウントで構成されているなど) もこの呼び出しで返されるようにできます。
bool CALLBACK ProductEnumerationCallback(const XStoreProduct* product, void* context)
{
// Handle adding the product to the game
printf("%s %s %u\n", product->title, product->storeId, product->productKind);
return true;
}
void QueryCatalog()
{
auto async = new XAsyncBlock{};
async->queue = m_asyncQueue;
async->callback = [](XAsyncBlock* async)
{
XStoreProductQueryHandle queryHandle = nullptr;
HRESULT hr = XStoreQueryAssociatedProductsResult(async, &queryHandle);
if (SUCCEEDED(hr))
{
hr = XStoreEnumerateProductsQuery(queryHandle, async->context, ProductEnumerationCallback);
if (SUCCEEDED(hr))
{
printf("Enumeration complete\n");
}
XStoreCloseProductsQueryHandle(queryHandle);
delete async;
}
};
XStoreProductKind typeFilter =
XStoreProductKind::Consumable |
XStoreProductKind::Durable |
XStoreProductKind::Game;
HRESULT hr = XStoreQueryAssociatedProductsAsync(
m_xStoreContext,
typeFilter,
UINT8_MAX, // placeholder maximum, see Paging
async)
if (FAILED(hr))
{
delete async;
}
}
注意事項
- 購入可能な製品のみが
XStoreQueryAssociatedProductsAsync
で返されます; バンドルでのみ許可される製品か、または個別に購入可能に設定されていない製品は返されません。 これらの使用方法はXStoreQueryProductsAsync
以下に説明します。 - 返される製品の数についての事前情報はないため、製品数を累積する必要があります。
Paging
ページングの処理が省略可能になりました。 渡す最大値を選択します。この値は、カタログの有効期間予想サイズを超えることになります。 大規模なカタログの場合、または進行状況を表示するための結果処理のセグメント化を設計している場合は、ページングの検出と処理を実装できます。 詳細については、「XStoreQueryAssociatedProductsAsync」を参照してください。
その他のオプション
ストア ID が既知またはその他の actionFilters
が必要な場合、XStoreQueryProductsAsync は特定の製品のクエリに使用できます。
「アクション」は製品に適用される使用シナリオです。これには、購入、ライセンス付与、ギフト、引き換え などの動詞があります。
XStoreQueryAssociatedProductsForStoreIdAsync を使用して、他のゲームに関連付けられている製品のクエリを実行できます。 これは、たとえば、別のタイトルのアドオンをクロスセルする場合に便利です。
XStoreQueryProductForCurrentGameAsync は、現在実行中のゲームの製品のみをクエリします。
XStoreShowAssociatedProductsUIAsync は、ユーザーを Microsoft Store アプリに移動し、関連情報を表示します。これは製品の種類でフィルタ処理できます。 これは、ゲーム内インターフェイスに存在する利用可能な製品を列挙する代わりに使用できます。
2. 製品に含まれているものを評価する
これには基本的に上記と同じコードが含まれていますが、次の変更点があります。
- XStoreQueryAssociatedProductsAsync → XStoreQueryEntitledProductsAsync
- XStoreQueryAssociatedProductsResult → XStoreQueryEntitledProductsResult
これらの API では、結果は、呼び出し元ユーザーのアカウントによって特別に資格を与えられている製品から構成されます。 資格は、直接所有していることを意味しますが、親バンドルまたはサブスクリプションを所有することによっても満たされていることも意味します。
XStoreProduct には資格を与えられると true に設定される isInUserCollection
フィールドが含まれているため、これは XStoreQueryAssociatedProductsAsync (および関連する関数) の結果によっても判定できます。
消費型アイテムの所有権
消費型アイテムの数量は XStoreProduct.skus[i].collectionData.quantity
に記載されています。
通常、消費型アイテムの SKU は 1 つのみです。
数量は、XStoreQueryConsumableBalanceRemainingAsync を使用して個別に問い合わせることもできますが、多数の消費型アイテムのを個別に問い合わせると、毎回サービス呼び出しが発生するためお勧めしません。
また、消費ベースのエコシステムの整合性を維持するために、消費型アイテムのサービス検証と引き換えの活用を強くお勧めします。 詳細については、「消費ベースのエコシステム」をご覧ください。
非消費型アイテムの所有権
ゲーム内で製品を使用する資格を与えられているかどうかを判断するには、アカウントがその製品を所有しているかどうかを確認するだけでは不十分です。 非消費型アイテムは、「ゲームの製品共有モデル」に記載されているコンテンツ共有ポリシーに準拠する必要があります。
XStoreAcquireLicenseForPackageAsync は、パッケージ付きの非消費型アイテムに使用され、コンテンツ共有の規定に従って、ライセンス供与可能かどうかを判定します。
XStoreAcquireLicenseForDurablesAsync は、パッケージのない非消費型アイテムに使用され、同じ動作を実行します。
XStoreQueryAddOnLicensesAsync は、デジタル ライセンス供与されたゲームに使用して、ライセンス供与可能な非消費型アイテム (パッケージなし) の一覧を返すことができます。
詳細については、「ダウンロード コンテンツの管理とライセンス」および「パッケージなしの非消費型アイテムを使用する方法」をご覧ください。
3. 購入可能な製品を購入する
購入可能製品の購入フローを示すことは、Store ID を XStoreShowPurchaseUIAsync API に渡すのと同じくらいシンプルです。
void MakePurchase(const char* storeId)
{
auto async = new XAsyncBlock{};
async->context = &storeId;
async->queue = m_asyncQueue;
async->callback = [](XAsyncBlock *async)
{
const char* = reinterpret_cast<const char*>(async->context);
HRESULT hr = XStoreShowPurchaseUIResult(async);
if (SUCCEEDED(hr))
{
printf("Purchase succeeded (%s)\n", storeId);
// Refresh ownership and update game
}
else
{
printf("Purchase failed (%s) 0x%x\n", storeId, hr);
if (hr == E_GAMESTORE_ALREADY_PURCHASED)
{
printf("Already own this\n");
}
}
delete async;
};
HRESULT hr = XStoreShowPurchaseUIAsync(
m_xStoreContext,
storeId,
nullptr, // Can be used to override the title bar text
nullptr, // Can be used to provide extra details to purchase
async);
if (FAILED(hr))
{
delete async;
printf("Error calling XStoreShowPurchaseUIAsync : 0x%x\n", hr);
return;
}
}
非同期コールバックで予定されている購入の結果を処理することに加えて、Microsoft Store に明示的に切り替えることによってゲーム外で購入することもできます。 Xbox.com、PC、モバイル アプリなどのアウトレットでも購入できます。 初期署名フローの一部だけではなく、ゲーム内ストアや設定内のどこかに移行するなど、オンデマンドで製品の所有権を確実に更新するゲーム内の場所を用意することをお勧めします。