Backend Integration
Custom asset server integration
It is possible to load items/currencies from a custom asset server and use them as tournament rewards or entry fees.
Also, any sign up can be routed through a custom server that can deduct those items or reject tournament signup (e.g. user does not have enough currency).
Login with custom server
In order to authenticate login via custom server an HTTP endpoint has to be created that returns user basic info in a specific, JSON format.
You have to do this if you want to have your user IDs associated with tournament account.
Associated user IDs will then be provided in other custom server integration calls (e.g. reporting tournament results to custom server).
Data passed from the client for user authetication will be attached as application/x-www-form-urlencoded
.
Send data from client that are needed for user authentication (e.g. clinet token).
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;
Check passed data from client and determine if user is valid.
You have to respond with JSON format that contains your user ID and user nick.
JavaScript
{
"id": "123",
"nickName": "nick"
}
The endpoint also has to respond with status code 200.
Once there is a endpoint that returns the required format, navigate to Game Settings/Authentication providers
and enable custom authentication
.
Insert a valid HTTP path and add any necessary headers/parameters for authentication required by your server.
Loading store items from server
In order to load items and currencies from the custom server an HTTP endpoint has to be created that returns items in a specific, JSON format.
You have to do this to make sure that the server loads the items for internal use and marks those items/currencies as "loaded" from the external resource.
JSON format:
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"
}]
}
The endpoint also has to respond with status code 200.
Always return all items you wish to import.
Items/currencies that already exist will be updated.
Once there is a endpoint that returns the required format, navigate to Game Settings/Store Integration
and enable "external store hookup".
Select Custom URL
provider.
Insert a valid HTTP path and add any necessary headers/parameters for authentication required by your server.
Click on the Sync data now
button which will import your items/currencies.
You should now be able to access imported items when you are editing your tournament template rewards and entry fees.
If there are any updates to your assets just import them again by clicking on the Sync data now
button.
Signup via custom server
In order to route tournament signups through a custom server, an HTTP endpoint has to be created that accepts a specific, JSON format.
On every user signup, a call will be made to a custom server with a payload containing information about the tournament, user, entry fees, etc.
The HTTP call is POST with a parameter called userTicket containing the JSON payload.
JSON format:
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
}]
}
}
A successful response is then awaited with HTTP status code 200 (or another code in case of rejection).
Once there is a endpoint that accepts the required JSON format navigate to: Game Settings/Tournament settings Integration
and enable "external signup".
Insert a valid HTTP path and add any necessary headers/parameters for authentication required by your server.
After this setup, any signup from a client should be routed through the custom server before it's accepted and confirmed.
Tournament result report to custom server
To receive tournament results via a custom server, an HTTP endpoint has to be created that accepts a specific, JSON format.
After every tournament finishes, a call will be made to a custom server with a payload containing information about the tournament, users and their prizes, etc.
The HTTP call is POST with a parameter called jsonPayload containing JSON payload.
JSON format:
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"}]
}]
}
A successful response is then awaited with HTTP status code 200.
In case of failure, it will be repeated several times.
Once there is an endpoint that accepts the required JSON format, navigate to: Game Settings/Tournament settings Integration
and enable "external prize delivery".
Insert a valid HTTP path and add any necessary headers/parameters for authentication required by your server.
PlayFab asset server integration
It is possible to load items/currencies from a PlayFab backend and use them as tournament rewards or entry fees.
Also, any sign up can be routed through a custom cloud script that can deduct those items or reject tournament signup (e.g. user does not have enough currency).
Create PlayFab secret key
For PlayFab integration you will need TitleId and SecretKey.
Login to your playfab dashboard, select your desired game and open settings screen.
You can find TitleId in API Features
tab. You can create a new SecretKey in Secret Key
tab.
Do not set expiration date for secret key as that could cause outtage for your game in case you forget to set new one in tournament dashboard.
Login with PlayFab provider
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));
To get associated playfab id with user account call BackboneManager.Client.User.GetLoginId(LoginProvider.Platform.Playfab)
.
This can be used to compare if logged playfab client matches with logged tournament client.
Loading store items from Playfab
Navigate to Game Settings/Store Integration
and enable "external store hookup".
Select Playfab
provider.
Insert a valid title id & secret key and save chages.
If there are any updates to your assets just import them again by clicking on the Sync data now
button.
Signup via Playfab CloudScript
In order to route tournament signups through a Playfab CloudScript, an function has to be created that accepts a specific, JSON format.
On every user signup, a call will be made to this cloudscript funtion with a payload containing information about the tournament, user, entry fees, etc.
The CloudScript function parameter args will contain the JSON payload.
JSON format:
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
}]
}
}
Here is an example CloudScript function that handles signup/signout:
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 };
};
A successful response is then awaited in form { success: true } (or anything else in case of rejection).
Once there is a CloudScript function that accepts the required JSON format navigate to: Game Settings/Tournament settings Integration
and enable "external signup".
Select Playfab
provider.
Insert a valid title id, secret key, CloudScript function name, function version (revision number) and save changes.
There is pre-generated server secret that you can change if you want to.
Use this secret in cloud script to prevent playfab user clients to execute it.
After this setup, any signup from a client should be routed through the cloud script before it's accepted and confirmed.
Tournament result via Playfab CloudScript
To receive tournament results via a Playfab CloudScript, an function has to be created that accepts a specific, JSON format.
After every tournament finishes, a call will be made to this cloudscript funtion with a payload containing information about the tournament, users and their prizes, etc.
The CloudScript function parameter args will contain the JSON payload.
JSON format:
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"}]
}]
}
Here is an example CloudScript function that handles prize delivery:
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);
}
}
}
};
A successful response is then awaited with HTTP status code 200.
In case of failure, it will be repeated several times.
Once there is an endpoint that accepts the required JSON format, navigate to: Game Settings/Tournament settings Integration
and enable "external prize delivery".
Select Playfab
provider.
Insert a valid title id, secret key, CloudScript function name, function version (revision number) and save changes.
There is pre-generated server secret that you can change if you want to.
Use this secret in cloud script to prevent playfab user clients to execute it.
Game server integration
Submit game session result from custom server
In order to process results from external server first navigate to: Game Settings/Tournament settings Integration
and enable "external result submission".
To submit game session result from dedicated server or custom backed a specific HTTP call has to be made.
The HTTP call is POST and the format has to be application/x-www-form-urlencoded
.
Endpoint URL:
https://backbone-client-api.azurewebsites.net/api/v1/gameSessionSetResultFromServer
Headers:
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 parameters:
gameSessionData
gameSessionData
value has to be JSON string (do not include comments):
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"
}
]
}
Get match data from server
Query tournament match data from game server.
Endpoint URL:
https://backbone-client-api.azurewebsites.net/api/v1/tournamentGetMatchDataForServer
Headers:
BACKBONE_APP_ID: YOUR-TSDK-GAME-CLIENT-ID
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
application/x-www-form-urlencoded parameters:
accessToken
tournamentId
matchId
accessToken
value has to be SERVER ACCESS TOKENtournamentId
value has to be id of tournament match belongs tomatchId
value has to be id of specific tournament match
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"
}
]
}
- Custom asset server integration
- Login with custom server
- Loading store items from server
- Signup via custom server
- Tournament result report to custom server
- PlayFab asset server integration
- Create PlayFab secret key
- Login with PlayFab provider
- Loading store items from Playfab
- Signup via Playfab CloudScript
- Tournament result via Playfab CloudScript
- Game server integration