Amazon GameOn: Usage Overview

The Amazon GameOn API gives you the chance to easily add tournaments, leaderboards and prizes into your game, engaging users across all platforms that the game is published to.

In this article we'll be showing you how to get it all working in GameMaker Studio 2, but before continuing you must already have a game set up on the GameOn dashboard and be able to log in to the GameOn API. If this is not the case, then please see the following article before going any further:

This article assumes that you have already created one or more tournaments and so won't be covering that aspect of things, but if you haven't yet set up a tournament then you should do that before continuing with this article. The Amazon documentation provides a complete step-by-step guide here:

We also assume that you have correctly set up any requirement groups and prizes that your project may require, but if you haven't already done that then you can find a brief overview of how to use the GameOn Admin API to set it up here:

 

IMPORTANT! While the GameOn asset supports player Teams, the actual setup and implementation of them is outside the scope of the documentation. If you wish to use this feature you should see the Amazon documentation from the link below:

 

Once You're All Set Up...

We will now walk you through the basic use of the GameOn API in GameMaker Studio, showing a typical workflow and some example code. Note that this is not strictly speaking a tutorial, as the GameOn API is designed to be as flexible as possible when used and there is no "right" way to do something... it'll depend largely on how you structure your game and how you like to code. As such, the examples shown here are simply to show the most basic usage and get you started, and in many cases simply use show_debug_message() to illustrate returned data.

Also note that all examples use delegate instances for the callback returns, which for simplicity in the examples is the same ID as the instance that generated the callback, but you can use any other delegate instance or callback scripts as required. 

  • For a full list of the API scripts and objects, please see the PDF manual included with the GameOn asset.

 

Data Instances

In the "Setting Up" article we talked about promises as a way to store and parse data in an asynchronous manner when we call a GameOn script, but what wasn't mentioned is that many promises also return other instances as part of their operation. These instances are called data instances and are used throughout the Amazon GameOn asset as a way to store and retrieve information about the various different aspects of a tournament, or a prize, or the player, etc...

GameOn_DataInstances.png

At various times in the code examples shown below we will be using these data instances to get information, but you should note that, unlike promises, data instances are automatically destroyed when the promise they are stored in is destroyed. You do not need to clean these up manually and if you want to keep them around then simply don't destroy the promise instance.

 

Get Tournament Data

Once you have the player logged-in, you'll probably want to get the list of applicable tournaments that they can join. For that we'll use the script gameon_tournament_query() as shown here:

if gameon_is_logged_in()
    {
    var _promise = gameon_tournament_query();
    if(gameon_util_object_exists(_promise))
         {
         _promise.delegate_instance = id;
         _promise.delegate_event_success = 0;
         _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn tournament query promise could not be generated.");
        }
    }

Here we call it with no arguments and so the returned promise will request all the available tournaments for the project, with no requirement groups assigned. It can also be called with any of the optional arguments to get the data for a single tournament or to filter the results in multiple ways (see the GameOn asset PDF manual for precise details).

In the above example, the promise will trigger a user event when it is completed, and in that we can get the tournament data:

var _p = delegate_current_promise;
var _tournament_list = _p.request_result_data_parsed;
for (var i = 0; i < ds_list_size(_tournament_list); ++i;)
    {
    if _tournament_list[| i].canEnter == true
        {
        var _id = _tournament_list[| i].tournamentId;
show_debug_message("Tournament Id = " + string(_id.tournamentId));
show_debug_message("Tournament Title = " + string(_id.title));
show_debug_message("Player Can Enter = " + string(_id.canEnter));
        }
    }
gameon_util_object_destroy(_p);

In this example code we are looping through the contents of the parsed data list for the data instance IDs of the GameOn object "oGameOnTournament". When we parse this list we check the variable "canEnter" and if that is true we then show some of the returned data in the output console for the tournament. 

NOTE: You can see all the different return values by opening the Create Event of the object oGameOnTournament.

Once you have a list of all tournament ID strings you can then supply them to gameon_tournament_query() again if you wish, but this time including a tournament's ID as the first argument, to get back a data instance specific to that tournament. When doing this, instead of a list of tournaments in the "request_result_data_parsed" variable, you'll get back a data instance ID for an instance of "oGameOnTournament", which can then be parsed as required.

 

Finding Tournaments That Meet Specific Requirements

If you need to get the tournaments with certain requirements - for example, you have a player at level 15 and you want to add them to tournaments with a requirement for players to be between levels 10 and 20 - then you need to add DS map with the requirement details to the function.

In it's simplest form it would look something like this:

if gameon_is_logged_in()
    {
    var _attributes = ds_map_create();
    _attributes[? "rng"] = current_player_range;
    var _promise = gameon_tournament_query(undefined, _attributes);
    ds_map_destroy(_attributes);
    if(gameon_util_object_exists(_promise))
         {
         _promise.delegate_instance = id;
         _promise.delegate_event_success = 0;
         _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn tournament query promise could not be generated.");
        }
    }

In this example "rng" maps to a range type requirement group that we previously created. Now when this is called you will get all the tournaments with no requirements, as well as the ones that the fit the requirements specified, and the promise will return the tournaments, as shown in the code previously.

IMPORTANT! The GameOn API does not track player attributes. It is up to you to track things like level, status, location or whatever metric it is that your game uses.

You can find the Amazon documentation for the Get Tournaments endpoint here:

 

Get Prize Bundles

When you query a tournament there will also be data returned about any Prize Bundles associated with it. This data is sent automatically when you ask for tournament data and can be retrieved by accessing the prizeBundles variable in the returned oGameOnTournament data objects. This list will contain prize data instance IDs.

var _id = _tournament_list[| 0].tournamentId;
var _bundle_list = _id.prizeBundles;
if _bundle_list != undefined
{
for (var i = 0; i < ds_list_size(_bundle_list); ++i;)
{

var _prize_data = _bundle_list[| i];
show_debug_message("Prize Bundle Title = " + string(_prize_data.title));
for (var j = 0; j < ds_list_size(_prize_data.prizeIds); ++j;)
{
show_debug_message("Prize ID " + string(j) + " = " + string(_prize_data.prizeIds[| j]));
}
}
}
 

In the above example we simply print out the prize IDs to the console, but you can use them to get information about individual prizes using the script gameon_prize_query(), as explained below.

 

Get Prize Data

If your tournament has prizes then you'll want to get information about them to show to the player. For that, you need to call the script gameon_prize_query():

if gameon_is_logged_in()
    {
    var _promise = gameon_prize_query(global.prize_id);
    if(gameon_util_object_exists(_promise))
        {
        _promise.delegate_instance = id;
        _promise.delegate_event_success = 0;
        _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn prize get promise could not be generated.");
        }
    }

When you use this script you supply a prize ID string, which you can retrieve by querying the prize bundle data returned when you queried the tournament data (see the section above). The script will generate a callback and return a promise where the request_result_data_parsed is a DS list holding the data instance IDs of the object oGameOnPrize, where each instance is a single prize from the bundle:

var _p = delegate_current_promise;
var _prize_list = _p.request_result_data_parsed;
for (var i = 0; i < ds_list_size(_prize_list); ++i;)
    {
    var _prize_data = _prize_list[| i];
    show_debug_message("Prize title: " + string(_prize_data.title));
    show_debug_message("Prize description: " + string(_prize_data.description));
    if sprite_exists(global.Prize_Sprite)
{
sprite_delete(global.Prize_Sprite);
}
else
{
global.Prize_Sprite = sprite_add(_prize_data.imageUrl, 0, false, false, 0, 0);
}
    }
gameon_util_object_destroy(_p);
 

You can then use this information to display the available prizes to the player. 

You can find the Amazon documentation for the Get Prize Details endpoint here:

 

Entering A Tournament

Once you have the list of available tournaments you'll want to present these to the player in some way and permit them to select one of them to enter. This selection would use the script gameon_tournament_enter():

if gameon_is_logged_in()
    {
    var _promise = gameon_tournament_enter(_tournament_list[| num]);
    if(gameon_util_object_exists(_promise))
         {
         _promise.delegate_instance = id;
         _promise.delegate_event_success = 0;
         _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn tournament entry promise could not be generated.");
        }
    }

This will return a promise which will trigger the user events for the delegate instance when the callback has been completed. If the promise has succeeded, then you will need to retrieve the unique match ID from the returned data object (oGameOnMatchEntry) and then store it, as this will be required for all further match API calls:

var _p = delegate_current_promise;
var _match_data = _p.request_result_data_parsed;
global.match_id = _match_data.matchId;
gameon_util_object_destroy(_p);

This simply gets the match ID from the data instance that the promise returns and then stores it in a global variable for further use. This match ID will be associated with the player for the duration of the tournament, and so in subsequent runs of the game you can simply use the same match ID until the tournament finishes or the player has no attempts left.

Note that if the player has used up all their permitted attempts for the given tournament the script will trigger a fail callback.

You can find the Amazon documentation for the Enter Tournaments endpoint here:

 

Querying A Match

Since match IDs perpetuate over multiple games, if the player leaves the game and comes back again it will be necessary to retrieve the ID of any match that is currently in progress. Or, you may want to have multiple matches and permit the user to pick and choose which one to participate in, and so want a list of all active matches. This can be done using the script gameon_match_query():

if gameon_is_logged_in()
    {
    var _promise = gameon_match_query();
    if(gameon_util_object_exists(_promise))
        {
        _promise.delegate_instance = id;
        _promise.delegate_event_success = 0;
        _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn match score promise could not be generated.");
        }
    }

This script can be called with optional arguments so that you can specify whether to retrieve all the current match IDs or whether to get the data on just a single match, as well as specify player attributes to check against the required groups for the tournament.

Here is an example for checking a single tournament using player attributes:

var _attributes = ds_map_create();
_attributes_map[? "val"] = "1";
_attributes_map[? "rng"] = "15";
promise = gameon_match_query(global.Match_ID, _attributes);
ds_map_destroy(_attributes);

Both types of call will return a promise which will trigger the user events for the delegate instance when the callback has been completed. If the promise has succeeded, then you will get back as the request data either the data object ID for oGameOnMatch or for oGameOnMatchList, depending on whether you are querying a single match ID or wanting to get a list of all of them.

If you are querying a list, then you would deal with it like this:

var _p = delegate_current_promise;
var _match_data = _p.request_result_data_parsed;
var _match_list = _match_data.matches;
if ds_exists(_match_list, ds_type_list)
    {
    for (var i = 0; i < ds_list_size(_match_list); ++i;)
        {
        if gameon_util_object_exists(_match_list[| i])
            {
            with (_match_list[| i])
                {
                show_debug_message("tournament instance = " + string(tournament));
               show_debug_message("attemptsRemaining = " + string(attemptsRemaining));
               show_debug_message("matchId = " + string(matchId));
               show_debug_message("lastScore = " + string(lastScore));
               show_debug_message("lastScoreDate = " + string(lastScoreDate));
               show_debug_message("scoreOverall = " + string(scoreOverall));
               show_debug_message("scoreOverallDate = " + string(scoreOverallDate));
               }
            }
        }
    }

So, the result data is an instance ID for an oGameOnMatchList data object with a DS list in the variable "matches". This list will contain the instance IDs of one or more oGameOnMatchEntry data objects, which can then be parsed to get the match ID or other information. Note that for each oGameOnMatchEntry instance there will be a variable "tournament", which is an ID for the data object oGameOnTournament and which you can parse to get the full tournament data that the match is part of.

If you are querying a single match, then you would parse the returned promise more like this:

var _p = delegate_current_promise;
var _match_data = _p.request_result_data_parsed;
with (_match_data.matches)
    {
    show_debug_message("tournament instance = " + string(tournament));
    show_debug_message("attemptsRemaining = " + string(attemptsRemaining));
    show_debug_message("matchId = " + string(matchId));
    show_debug_message("lastScore = " + string(lastScore));
    show_debug_message("lastScoreDate = " + string(lastScoreDate));
    show_debug_message("scoreOverall = " + string(scoreOverall));
    show_debug_message("scoreOverallDate = " + string(scoreOverallDate));
    }

Once you get the success callback you can then enter the game as normal.

You can find the Amazon documentation for the Get Matches endpoints here:

 

Querying Match Prizes

If the tournament has prizes you will also need to call the script gameon_match_query() when the tournament has ended to check and see if any of the prizes should be awarded to the player. The script call is the same as shown in the section above, only now the callback promise would be parsed for prize data. Something like this:

var _p = delegate_current_promise;
var _match_data = _p.request_result_data_parsed;
with (_match_data)
    {
if awardedPrizes != undefined
{
for (var i = 0; i < ds_list_size(awardedPrizes); ++i;)
{
var _prize_id = awardedPrizes[| i];
   show_debug_message("Prize Title = " + prizeTitle);
    show_debug_message("Prize Status = " + status);
}
}
   }

The important data here is the prize "status". This will be one of the following strings:

  • UNCLAIMED
  • CLAIMED
  • FULFILLED

The status string along with the prize ID value can later be used to claim the prize. This is covered later in the article, under the section Awarding A Prize.

You can find the Amazon documentation for Awarded Prizes here:

 

Entering A Match

A match is an instance of the tournament that has a specific number of maximum users. This is something that you set when you created the tournament using the GameOn dashboard:

GameOn_MatchSetup.png

The basic flow for the player would be as follows:

  • Player selects a tournament to enter
  • The game retrieves a match ID for the tournament
  • Player tries to enter the match
  • If the entry succeeds, the game starts and they play until they die (or whatever ends the run-through)
  • The game sends the player score for this tournament match
  • (Optional) The game shows the player the match results.

So, once you have a match ID, you need to have the player try to enter the match (either automatically, or explicitly through a button), using the script gameon_match_enter():

if gameon_is_logged_in()
    {
    var _promise = gameon_match_enter(global.match_id);
    if(gameon_util_object_exists(_promise))
         {
         _promise.delegate_instance = id;
         _promise.delegate_event_success = 0;
         _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn match entry promise could not be generated.");
        }
    }

You can then check for success or failure in the delegate instance (or scripts), where a success means you can start the actual game (which will automatically decrement the tournament attempts remaining for the player) and a failure means that something went wrong and you should either try again, or show a message to the user, or whatever is required by your game.

Note that a failure can be caused by the user having no attempts left for the tournament selected, in which case you should have something in place to deal with that in the "failure" event or script.

The data object for a success is oGameOnMatchEntry.

If the match is for a tournament that has requirement groups, then you should add these into the gameon_match_enter() script call like this:

var _attributes = ds_map_create();
_attributes_map[? "val"] = "1";
_attributes_map[? "rng"] = "15";
promise = gameon_tournament_enter("ca35cb63-3345-4e6d-98eb-e51ebd1b9590", undefined, _attributes_map);
ds_map_destroy(_attributes);

You can find the Amazon documentation for the Enter Match endpoint here:

 

Submitting A Score

When the match is finished, the next thing you'll want to do is submit the player's score to the leaderboards for the tournament. For that you'd use the script gameon_match_score(match, score):

if gameon_is_logged_in()
    {
    var _promise = gameon_match_score(global.match_id, obj_Player_points);
    if(gameon_util_object_exists(_promise))
         {
         _promise.delegate_instance = id;
         _promise.delegate_event_success = 0;
         _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn match score promise could not be generated.");
        }
    }

As with the other scripts, this will create a promise callback for either success or failure which will need parsing. In this case, a success will only return a single value, which is the current highest score for the player:

var _p = delegate_current_promise;
global.HighScore = _p.request_result_data_parsed;
gameon_util_object_destroy(_p);

Note that the score will be submitted using the system-generated name unless you have previously set the player name yourself using the gameon_player_update() script (which we recommend to get more personalised and engaging leaderboards).

You can find the Amazon documentation for the Submit Score endpoint here:

 

Add Match Attempts

It may be that you want to give your players another chance at a tournament match after their permitted attempts have already been used up - e.g., as a reward or as part of a challenge - in which case you can call the script gameon_match_attempts() with an argument for the number of extra attempts to give:

if gameon_is_logged_in()
    {
    var _promise = gameon_match_attempts(global.match_id, 1);
    if(gameon_util_object_exists(_promise))
        {
        _promise.delegate_instance = id;
        _promise.delegate_event_success = 0;
        _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn match attempts promise could not be generated.");
        }
    }

When this succeeds, the callback event will return you the new number of remaining attempts for the player. This can then be shown to the user so they know how many attempts they have left: 

var _p = delegate_current_promise;
var _num = _p.request_result_data_parsed;
show_debug_message("Number of attempts increased to " + string(_num));
gameon_util_object_destroy(_p);

 You can find the Amazon documentation for the Add Attempts endpoint here:

 

Get The Leaderboard Data

It's not much good having the user participate in tournaments if they can't see how they're doing compared to other people, and so the GameOn API has a script gameon_match_leaderboard
()
 that can be used to get leaderboard data which can then be shown to the player:

if gameon_is_logged_in()
    {
    var _promise = gameon_match_leaderboard(global.match_id);
    if(gameon_util_object_exists(_promise))
        {
        _promise.delegate_instance = id;
        _promise.delegate_event_success = 0;
        _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn match attempts promise could not be generated.");
        }
    }

This is the simplest way to request leaderboard data, and it will return the leaderboard (up to 100 entries) and the data object oGameOnLeaderboard, which can then be parsed to get data:

var _p = delegate_current_promise;
var _leaderboard_data = _p.request_result_data_parsed;
var _player_data = _leaderboard_data.currentPlayer;
show_debug_message("Player: " + string(_player_data.playerName));
show_debug_message("Score: " + string(_player_data.leaderboardScore));
show_debug_message("Rank: " + string(_player_data.rank));

var _leaderboard = _leaderboard_data.leaderboard;
for (var i = 0; i < ds_list_size(_leaderboard); ++i;)
    {
    var _lb_inst = _leaderboard[| i];
    show_debug_message("Leaderboard Rank: " + string(_lb_inst.rank));
    show_debug_message("Player: " + string(_lb_inst.playerName));
    show_debug_message("Score: " + string(_lb_inst.leaderboardScore));
    if _lb_inst.isCurrentPlayer
        {
        show_debug_message("This is the current player!");
        }
    }
gameon_util_object_destroy(_p);

In this case, we get one oGameOnLeaderboard which links to various instances of oGameOnLeaderboardItem - one for the player data, and then a list of them for each ranking in the leaderboard. Note that the ranking may also include the player score, and this can be checked using the isCurrentPlayer variable, which will be true if the rank is for the player or false otherwise.

You can also supply three additional arguments when calling this function to:

  • retrieve only neighbouring scores
  • limit the amount of ranks returned
  • get the next page of results from a URL (this is only used when you have already called this function and the returned oGameOnLeaderboard instance has the "next" variable defined)

If you don't want to use these, or only want to use one of them, or are using scripts for callbacks instead of a delegate instance, then set those you don't want to use to undefined.

Note that when you supply a number for "neighbours" then the ranks returned will be +/- this amount around the player position, for example:

promise = gameon_match_leaderboard(global.match_id, 2);

The above code will generate a leaderboard request to get the 2 neighbouring scores above the player, the player's own ranking, and the 2 neighbouring scores below the player. Something like this:

6) Sven - 5699
7) Andrew - 5276
8) Natasha - 4813
9) John - 2774
10) Morag - 1056

This shows our current player, Natasha, is in 8th position and the two scores above and below.

To parse this data you'd have something like this:

var _p = delegate_current_promise;
var _leaderboard_data = _p.request_result_data_parsed;

var _neighbors= _leaderboard_data.neighbors;
for (var i = 0; i < ds_list_size(_neighbors); ++i;)
    {
    var _nb_inst = _neighbors[| i];
    show_debug_message("Leaderboard Rank: " + string(_nb_inst.rank));
    show_debug_message("Player: " + string(_nb_inst.playerName));
    show_debug_message("Score: " + string(_nb_inst.leaderboardScore));
    if _nb_inst.isCurrentPlayer
        {
        show_debug_message("This is the current player!");
        }
    }
gameon_util_object_destroy(_p);
 

As you can see, neighbour data is handled the same as the leaderboard data shown earlier.

It's worth noting that, depending on if you supply a neighbours argument or not, you only ever get returned either the list of neighbours or the general leaderboard list, not both.

You can find the Amazon documentation for the Get Leaderboard endpoint here:

 

Awarding A Prize

Once the tournament match is finished you'll want the award the player with any prizes that are relevant. To do this you would call the script gameon_prize_award(), supplying a DS list with the prize IDs that you wish to award the player with, along with a true/false argument to decide whether to fulfil the prize instantly or to store it and fulfil it on-demand later:

if gameon_is_logged_in()
    {
var _prize_list = ds_list_create();
ds_list_add(_prize_list, global.Prize_ID);
    var _promise = gameon_prize_award(_prize_list, true);
    if(gameon_util_object_exists(_promise))
        {
        _promise.delegate_instance = id;
        _promise.delegate_event_success = 0;
        _promise.delegate_event_failure = 1;
        }
    else
        {
        gameon_util_log("GameOn match attempts promise could not be generated.");
        }
    }


If successful, the callback promise will return a data instance oGameOnPrizeClaim, which can be parsed like this:

var _p = delegate_current_promise;
var _prize_data = _p.request_result_data_parsed;
var _prizes = _prize_data.prizes;
for(i = 0; i < ds_list_size(_prizes); ++i;)
{
var _prize = _prizes[| i];
show_debug_message("Prize match ID: " + string(_prize.matchId));
show_debug_message"Prize status: " + string(_prize.status));
show_debug_message("Prize info: " + string(_prize.prizeInfoType));
}
gameon_util_object_destroy(_p);

The data object has a DS list with the instance IDs of all the relevant prize data objects oGameOnPrizeClaimItem, and this object is then parsed to get the individual prize data, which can be stored and used to check and update the player data. The prize status will be one of the following:

  • "CLAIMED": This will be returned the first time a prize is awarded.

  • "RECLAIMED": This will be returned all subsequent times you try to award the prize after the initial award.

  • "FULFILLED": This will be returned if you set the script to fulfil the prize instantly.

Note that you can claim a prize but not fulfil it by calling the gameon_prize_award() script with the "fulfil" argument set to false. When you want the player to receive the prize you will need to call the script again but this time string the "fulfil" argument to true.

You can find the Amazon documentation for the Claim Prizes endpoint here:

 

Summary

That brings us to the end of this overview of the Amazon GameOn API. It might seem quite complex at first, but it's really just a straightforward flow like this:

  • Register Player
  • Get Tournament Info
  • Get Match Info
  • Enter The Player In Match
  • Submit Score
  • Show Leaderboard
  • Award Prizes (after tournament has ended)

As long as you plan a little bit ahead and adapt the above flow to suit the interface and characteristics of your game, you shouldn't have too many problems.

We also recommend that you take some time to revise and play with the demo project that accompanies the GameOn API scripts and objects. You can set things up on the GameOn dashboard and then add in the different ID values to the demo and get an idea for how things work.

One further thing to consider when using the GameOn API is that you can have a player generate their own tournaments. If you'd like to know more about this feature, please read the following article:

 

 

 

 

 

 

 

Have more questions? Submit a request

0 Comments

Article is closed for comments.