Backend Integration
カスタムアセットサーバー統合
カスタムアセットサーバーからアイテム・通貨を読み込み、トーナメントの賞金やエントリー料として使用できます。
また、これらのアイテムを差し引いたりトーナメントへのサインアップを拒否したりできる(例:ユーザーの所持金が足りないなど)カスタムサーバー経由ですべてのサインアップをルートできます。
カスタムサーバーでログイン
カスタムサーバーでログインを認証するためには、ユーザーの基本情報を特定のJSONフォーマットで返すHTTPエンドポイントを作成する必要があります。
トーナメントアカウントにユーザーIDを関連付けたい場合は、これを行わなければなりません。
関連付けられたユーザーIDは、他のカスタムサーバーとの統合コール(例:カスタムサーバーへのトーナメント結果の報告)で提供されます。
ユーザー認証のためにクライアントから渡されるデータは、application/x-www-form-urlencoded
として添付されます。
ユーザー認証に必要なデータをクライアントから送信します(例:クリネットトークン)。
C#
// coroutine
// ...
// use custom external login provider, pass custom data from your backend to authenticate user
var loginOperation = BackboneManager.Client.Login(LoginProvider.CustomExternal(
true,
MyBackend.Username,
new KeyValuePair<string, object>("clientToken", MyBackend.Token),
new KeyValuePair<string, object>("userId", MyBackend.Id)));
yield return loginOperation;
クライアントから渡されたデータをチェックし、ユーザーが有効かどうかを判断します。
ユーザーIDとユーザーニックネームを含むJSONフォーマットで応答する必要があります。
JavaScript
{
"id": "123",
"nickName": "nick"
}
また、エンドポイントはステータスコード200で応答する必要があります。
必要な形式を返すエンドポイントができたら、Game Settings/Authentication providers
に移動し、custom authentication
を有効にします。
有効なHTTPパスを挿入し、サーバーが必要とする認証のための必要なヘッダー/パラメータを追加します。
サーバーからストアアイテムを読み込む
アイテムや通貨をカスタムサーバーから読み込むためには、アイテムを特定のJSONフォーマットで返すHTTPエンドポイントを作成する必要があります。
サーバーがアイテムを内部使用のために読み込み、アイテムと通貨を外部リソースから「読み込み済」とマークするようにこの操作を行います。
JSON フォーマット:
JavaScript
{
items:[
{
id:"itemId1",
name:"itemName1",
image:"imageUrl (optional)"
},
{
id:"itemId2",
name:"itemName2",
image:"imageUrl (optional)"
}],
currencies:[
{
id:"currencyId1",
name:"currencyName1"
},
{
id:"currencyId2",
name:"currencyName2"
}]
}
エンドポイントはまた、status code 200 にレスポンスする必要があります。
常にインポートするすべてのアイテムを返します。
既に終了したアイテムと通貨は更新されます。
リクエストされるフォーマットで返すエンドポイントが表示されたら、Game Settings/Store Integration
へ移動し、「external store hookup」を有効にします。
プロバイダはCustom URL
を選択します。
有効なHTTPパスと、サーバーからリクエストされる認証用のヘッダ・パラメータを挿入します。
Sync data now
ボタンをクリックしてアイテムと通貨をインポートします。
トーナメントテンプレート賞とエントリー料の編集のときに、インポートしたアイテムにアクセスできるようになりました。
アセットにアップデートが生じた場合は、再度Sync data now
ボタンをクリックしてインポートを行ってください。
カスタムサーバー経由でのサインアップ
トーナメントサインアップをカスタムサーバーを通して計画するには、特定のJSONフォーマットを受け入れるHTTPエンドポイントを作成する必要があります。
各ユーザーのアインアップごとに、トーナメント、ユーザー、エントリー料などの情報が盛り込まれたペイロードでカスタムサーバーへのコールが行われます。
このHTTPコールは、JSONペイロードを含む userTicket と呼ばれるパラメータでのPOST送信です。
JSON フォーマット:
JavaScript
{
isSignup:true,
isSignout:false,
userId:"64bit number as string",
userExternalId:"string",
ticketId:"64bit number as string",
tournamentId:"64bit number as string",
customRequirements:[{
name:"string",
value:"string"
}],
fees:{
items:[{
id:"64bit number as string",
externalId:"string",
amount:1
}],
currencies:[{
id:"64bit number as string",
externalId:"string",
amount:1
}]
}
}
レスポンスが正常に行われると、HTTP status code 200 (拒否された場合は、別のコード)で待機状態となります。
リクエストされるJSONフォーマットを受け入れるエンドポイントができたら、Game Settings/Tournament settings Integration
へ移動し、「external signup」を有効にします。
有効なHTTPパスと、サーバーからリクエストされる認証用のヘッダ・パラメータを挿入します。
この設定を行ったあと、クライアントからのすべてのサインアップが受け入れおよび確認前にカスタムサーバー経由でルーティングされるようになります。
カスタムサーバーへのトーナメント結果レポート
カスタムサーバー経由でトーナメント結果を受信するには、特定のJSONフォーマットを受け入れるHTTPエンドポイントを作成する必要があります。
各トーナメントが終了するごとに、トーナメント、ユーザー、賞金などの情報が盛り込まれたペイロードでカスタムサーバーへのコールが行われます。
このHTTPコールは、JSONペイロードを含む jsonPayload と呼ばれるパラメータでのPOST送信です。
JSON フォーマット:
JavaScript
{
"tournamentId":"64bit number as string",
"prizes":[{
"ticketId":"64bit number as string",
"userId":"64bit number as string",
"userExternalId":"string",
"place":1,
"items":[{
"id":"64bit number as string",
"amount":1,
"externalId":"string"}],
"currencies":[{
"id":"64bit number as string",
"amount":1,
"externalId":"string"}]
}]
}
レスポンスが正常に行われると、HTTP status code 200 で待機状態となります。
失敗した場合、何度か繰り返されます。
リクエストされるJSONフォーマットを受け入れるエンドポイントができたら、Game Settings/Tournament settings Integration
へ移動します。
有効なHTTPパスと、サーバーからリクエストされる認証用のヘッダ・パラメータを挿入します。
PlayFabアセットサーバー統合
Playfabバックエンドからアイテム・通貨を読み込み、トーナメントの賞金やエントリー料として使用できます。
また、これらのアイテムを差し引いたりトーナメントへのサインアップを拒否したりできる(例:ユーザーの所持金が足りないなど)カスタムCloudScript経由ですべてのサインアップをルートできます。
PlayFab秘密鍵を作成する
PlayFab統合には、TitleId と SecretKey が必要となります。
playfabダッシュボードにログインして、ゲームを選択し、設定画面を開きましょう。
API Features
タブに TitleId があります。新しい SecretKey の作成はSecret Key
タブで行えます。
秘密鍵に有効期限を設定しないようにしてください。トーナメントダッシュボードで新しい秘密鍵を設定し忘れた場合、ゲームが停止状態になってしまいます。
PlayFabプロバイダ経由でログインする
If you integrating with PlayFab services we strongly recommend enabling only PlayFab login provider in tournament dashboard. Also NOTE that if you will not use PlayFab login provider other integration features such as tournament signup or delivering prizes via cloudscript fail to work.
Enter here TitleId & SecretKey and save changes.
In your game client, after you initialize and login with playfab you will get a session ticket.
This session ticket is then passed to playfab login provider to authenticate user and login to tournaments.
This process will ensure that system has correct and valid playfab id associated with user account.
C#
string playfabId;
string playfabSessionTicket;
bool isPlayfabLoginFinished;
// coroutine
// ...
// login playfab client
PlayFab.PlayFabClientAPI.LoginWithCustomID(
new PlayFab.ClientModels.LoginWithCustomIDRequest() {
CreateAccount = true,
CustomId = "customPlayfabId"
},
(result) =>
{
isPlayfabLoginFinished = true;
// get playfab user id and session ticket (we will use it for authentication)
playfabId = result.PlayFabId;
playfabSessionTicket = result.SessionTicket;
},
(error) =>
{
isPlayfabLoginFinished = true;
});
// wait until playfab login process finishes
yield return new WaitUntil(() => isPlayfabLoginFinished);
// use playfab login provider, pass playfab id and session ticket
yield return BackboneManager.Client.Login(
Gimmebreak.Backbone.User.LoginProvider.Playfab(
true,
"NickName-" + playfabId,
playfabSessionTicket,
playfabId));
playfab idをユーザーアカウントと関連付けるには、 BackboneManager.Client.User.GetLoginId(LoginProvider.Platform.Playfab)
を呼び出します。
記録されたPlayfabクライアントが記録されたトーナメントクライアントと一致するかの比較に使用されます。
Playfabからストアのアイテムを読み込む
Game Settings/Store Integration
へ移動して「external store hookup」を有効にします。
プロバイダはPlayfab
を選択します。
有効な title id と secret key を入力して変更を保存します。
Sync data now
ボタンをクリックして、アイテム・通貨を(プライマリカタログから)インポートします。
トーナメントテンプレート賞とエントリー料の編集のときにインポートしたアイテムにアクセスできるようになっているはずです。
アセットに何かしらのアップデートが生じた場合は、Sync data now
ボタンをクリックして再度インポートを行ってください。
Playfab CloudScript経由でのサインアップ
トーナメントサインアップをPlayfab CloudScript経由でルートするには、特定のJSONフォーマットを受け入れる関数を作成する必要があります。
各ユーザーがサインアップするごとに、トーナメント、ユーザー、エントリー料などの情報を含むペイロードで、このcloudscript関数への呼び出しが行われます。
CloudScript関数のパラメータである args には、JSONペイロードが含まれます。
JSON フォーマット:
JavaScript
{
serverSecret:"string",
isSignup:true,
isSignout:false,
userId:"64bit number as string",
userPlayfablId:"string",
ticketId:"64bit number as string",
tournamentId:"64bit number as string",
customRequirements:[{
name:"string",
value:"string"
}],
fees:{
items:[{
id:"64bit number as string",
externalId:"string",
amount:1
}],
currencies:[{
id:"64bit number as string",
externalId:"string",
amount:1
}]
}
}
サインアップ・サインアウトくを処理するCloudScript関数のサンプルです:
JavaScript
// This is a example tournament signup/signout handler. If signup is requested
// check if user can sign up and deduct any required fees. If signout is requested
// return any deducted fees back to users account.
handlers.tournamentSignup = function(args, context){
if (args.serverSecret == "secret") {
if (args.isSignup) {
// Check any custom requirement for the tournament. This can be
// e.g. having required minimum rank. If player does not meet
// specified criteria, the signup should be rejected.
for (var i = 0; i < args.customRequirements.length; i++) {
var name = args.customRequirements[i].name;
var value = args.customRequirements[i].value;
if (name == "testRequirement" &&
value == "reject") {
return { success: false };
}
}
// Check if user has required signup fees.
if (args.fees.items.length > 0 ||
args.fees.currencies.length > 0) {
// Get user inventory
var userInvetoryResult = server.GetUserInventory({PlayFabId: currentPlayerId});
// Check if user has enough currency
for (var i = 0; i < args.fees.currencies.length; i++) {
var currencyFee = args.fees.currencies[i];
var userCurrency = userInvetoryResult.VirtualCurrency[currencyFee.externalId];
if (!userCurrency ||
userCurrency < currencyFee.amount) {
// User does not have required currency or amount
return { success: false };
}
}
// Sort user invetory items by id
var userInventory = {};
for (var i = 0; i < userInvetoryResult.Inventory.length; i++) {
var item = userInvetoryResult.Inventory[i];
if (!userInventory[item.ItemId]) {
userInventory[item.ItemId] = [];
}
userInventory[item.ItemId].push(item);
}
// Check if user has enough items
for (var i = 0; i < args.fees.items.length; i++) {
var itemFee = args.fees.items[i];
var userItems = userInventory[itemFee.externalId];
if (!userItems ||
userItems.length < itemFee.amount) {
// User does not have required item or amount
return { success: false };
}
}
// Substract user's currencies
for (var i = 0; i < args.fees.currencies.length; i++) {
var currencyFee = args.fees.currencies[i];
server.SubtractUserVirtualCurrency({PlayFabId: currentPlayerId, VirtualCurrency: currencyFee.externalId, Amount: currencyFee.amount });
}
// Revoke user's items
var revokedItems = { Items: [] };
for (var i = 0; i < args.fees.items.length; i++) {
var itemFee = args.fees.items[i];
for (var p = 0; p < itemFee.amount; p++) {
revokedItems.Items.push({PlayFabId: currentPlayerId, ItemInstanceId: userInventory[itemFee.externalId][p].ItemInstanceId});
// Maximum 25 items can be removed at once (Playfab documentation)
// If container is filled with 25 items, revoke and continue
if (revokedItems.Items.length == 25) {
server.RevokeInventoryItems(revokedItems);
revokedItems.Items = [];
}
}
}
// Check if any items should be revoked (last 25 items)
if (revokedItems.Items.length > 0) {
server.RevokeInventoryItems(revokedItems);
}
// All fees deducted, confirm tournament signup
return { success: true };
}
else {
// No fees to deduct, confirm tournament signup
return { success: true };
}
}
if (args.isSignout) {
// Return user's currencies
for (var i = 0; i < args.fees.currencies.length; i++) {
var currencyFee = args.fees.currencies[i];
server.AddUserVirtualCurrency({PlayFabId: currentPlayerId, VirtualCurrency: currencyFee.externalId, Amount: currencyFee.amount });
}
// Return user's items
var returnItems = { PlayFabId: currentPlayerId, ItemIds: [], Annotation: "Returned tournament fee items. TournamentId: " + args.tournamentId };
for (var i = 0; i < args.fees.items.length; i++) {
var itemFee = args.fees.items[i];
for (var p = 0; p < itemFee.amount; p++) {
returnItems.ItemIds.push(itemFee.externalId);
}
}
// Check if any items should be returned
if (returnItems.ItemIds.length > 0) {
server.GrantItemsToUser(returnItems);
}
// User fees has been returned
return { success: true };
}
}
return { success: false };
};
レスポンスが正常に行われると、{ success: true }(拒否された場は別)で待機状態となります。
リクエストされるJSONフォーマットを受け入れる関数ができたら、Game Settings/Tournament settings Integration
へ移動し、「external signup」を有効にします。
プロバイダはPlayfab
を選択します。
有効な title id、secret key、CloudScript 関数名、関数バージョン (修正番号)を挿入し、保存します。
希望する場合は変更可能な、すでに生成されたサーバーシークレットがあります。
Playfabユーザーが実行するのを防ぐため、cloud scriptでこちらを使用してください。
この設定を行ったあと、クライアントからのすべてのサインアップが受け入れおよび確認前にCloud script経由でルーティングされるようになります。
Playfab CloudScript経由のトーナメント結果
Playfab CloudScript経由でトーナメント結果を受信するには、特定のJSONフォーマットを受け入れる関数を作成する必要があります。
各トーナメントが終わるごとに、トーナメント、ユーザー、賞金などの情報が盛り込まれたペイロードでcloudscript関数に呼び出しが行われます。
CloudScript関数パラメータである args にはJSONペイロードが含まれます。
JSON フォーマット:
JavaScript
{
"serverSecret":"string",
"tournamentId":"64bit number as string",
"prizes":[{
"ticketId":"64bit number as string",
"userId":"64bit number as string",
"userPlayfabId":"string",
"place":1,
"items":[{
"id":"64bit number as string",
"amount":1,
"externalId":"string"}],
"currencies":[{
"id":"64bit number as string",
"amount":1,
"externalId":"string"}]
}]
}
賞金の受け渡しを処理するCloudScript関数のサンプルです。:
JavaScript
// This is example tournament prize delivery handler. Once tournament is finished
// all results will be provided togather with information which items and currencies
// should be granted to user.
handlers.tournamentPrizeDelivery = function(args, context){
if (args.serverSecret == "secret" &&
args.prizes) {
for (var i = 0; i < args.prizes.length; i++) {
var prize = args.prizes[i];
// Grant user currency prizes
for (var p = 0; p < prize.currencies.length; p++) {
var wonCurrency = {
PlayFabId: prize.userPlayfabId,
VirtualCurrency: prize.currencies[p].externalId,
Amount: prize.currencies[p].amount
};
server.AddUserVirtualCurrency(wonCurrency);
}
// Grant user item prizes
var wonItems = {
PlayFabId: prize.userPlayfabId,
ItemIds: [],
Annotation: "Won items in tournament. Place: " + prize.place + " TournamentId: " + args.tournamentId
};
for (var p = 0; p < prize.items.length; p++) {
var itemPrize = prize.items[p];
for (var c = 0; c < itemPrize.amount; c++) {
wonItems.ItemIds.push(itemPrize.externalId);
}
}
if (wonItems.ItemIds.length > 0) {
server.GrantItemsToUser(wonItems);
}
}
}
};
レスポンスが正常に行われると、HTTP status code 200 で待機状態となります。失敗した場合、何度か再試行されます。
リクエストされるフォーマットで返すエンドポイントができたら、Game Settings/Tournament settings Integration
へ移動し、「external prize delivery」を有効にします。
プロバイダはPlayfab
を選択します。
有効な title id、 secret key、CloudScript関数名、関数バージョン (修正番号) を挿入して、保存します。
希望する場合は変更可能な、すでに生成されたサーバーシークレットがあります。
Playfabユーザーが実行するのを防ぐため、cloud scriptでこちらを使用してください。
ゲームサーバーの統合
カスタムサーバーからゲームセッションの結果を送信する
外部サーバーからの結果を処理するために、まず、Game Settings/Tournament settings Integration
に移動し、「external result submission」を有効にします。
専用サーバーまたはカスタムバックされたサーバーからゲームセッションの結果を送信するには、特定のHTTPコールを行う必要があります。
HTTPコールはPOSTで、フォーマットはapplication/x-www-form-urlencoded
でなければなりません。
エンドポイントURL:
https://backbone-client-api.azurewebsites.net/api/v1/gameSessionSetResultFromServer
ヘッダー:
BACKBONE_APP_ID: YOUR-TSDK-GAME-CLIENT-ID
ACCESS_TOKEN: YOU-WILL-BE-GIVEN-SERVER-ACCESS-TOKEN
Content-Type: application/x-www-form-urlencoded
application/x-www-form-urlencoded パラメーター:
gameSessionData
gameSessionData
値はJSON文字列でなければならない(コメントは含まない):
JavaScript
{
// this is 64 bit number as string, id is provided from create game session API call,
"gameSessionId":"491197014055328536",
// type of game session is anything you want between 0-127, default is 0
// e.g. 0 - 1v1 1 - 2v2 etc you can give certain type to your games
"type":"0",
// this is 64 bit number as string, id is provided from match object e.g. match.Id
// NB: NOT match.MatchId that is something different
"tournamentMatchId":"491196930559318805",
// time in seconds your game session lasted
"time":"100",
// list of users and their respective placements
"users":[
{
"teamId":"1",
"userId":"491174601636715209",
"place":"2"
},
{
"teamId":"2",
"userId":"491174351375178434",
"place":"1"
}
],
// game session stats e.g. what type of map was played (optional)
"gameStats":[
{
"statId":"2",
"textValue":"test"
}
],
// user game session stats, e.g. how much damage specific user did (optional)
"userStats":[
{
"statId":"1",
"userId":"491174351375178434",
"floatValue":"134.234"
},
{
"statId":"1",
"userId":"491174601636715209",
"floatValue":"12.234"
}
]
}
サーバーからマッチデータを取得する
ゲームサーバーからトーナメントの試合データを取得します。
エンドポイントURL:
https://backbone-client-api.azurewebsites.net/api/v1/tournamentGetMatchDataForServer
ヘッダー:
BACKBONE_APP_ID: YOUR-TSDK-GAME-CLIENT-ID
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
application/x-www-form-urlencoded パラメーター:
accessToken
tournamentId
matchId
accessToken
の値は、SERVER ACCESS TOKENでなければなりません。tournamentId
値は、マッチが属するトーナメントのIDでなければならない。matchId
値は特定のトーナメント戦のIDでなければならない
Response:
JavaScript
{
"id": "620604471341234",
"secret": "lz59JQiTfdgsdfg",
"deadline": "2022-09-09T13:06:33.797Z",
"matchId": 1,
"phaseId": 1,
"groupId": 1,
"roundId": 1,
"playedGameCount": 1,
"maxGameCount": 1,
"status": 8,
"users": [
{
"userId": "6156293913241234",
"userExternalId": "XXXX",
"userPlayfabId": "XXXX",
"teamId": 1,
"checkedIn": false,
"userScore": 0,
"teamScore": 0,
"userPoints": 0,
"teamPoints": 0,
"matchPoints": 0,
"matchWinner": false
},
{
"userId": "6203549123412344",
"userExternalId": "XXXX",
"userPlayfabId": "XXXX",
"teamId": 2,
"checkedIn": true,
"userScore": 0,
"teamScore": 0,
"userPoints": 0,
"teamPoints": 0,
"matchPoints": 0,
"matchWinner": false
}
],
"roundSettings": [
{
"partySize": 1,
"maxTeamsPerMatch": 16,
"minGameTime": 3,
"maxRoundTime": 6
}
],
"propertySettings": [
{
"name": "property1",
"value": "value1"
},
{
"name": "property2",
"value": "value2"
}
],
"gameSessions": [
{
"gameSessionId": "6206051532412344"
}
]
}
Back to top