Scoreboard API

Table of Contents

Games in Catalog have access to the scoreboard feature, posting high scores to our server and fetching them from it. Below you will find documentation for both Lua and C scoreboard APIs.

What games can use the Scoreboard API?

Scoreboard support is only available to games that are distributed via Panic in a Season or in Catalog.

Creating a scoreboard

In order to post scores, your game will need its own scoreboard (with a corresponding board ID).

Currently, only Panic can create scoreboards. Please email us with the following information.

  • Game’s bundle ID (eg. “com.studioname.gamename”)
  • Board’s friendly name (eg. “High Scores”)
  • Board’s ID (eg. “highscores” - no special characters)
  • Board type - daily or regular
  • Specify sorting of scores on board - ascending: low-to-high or descending: high-to-low
  • If there are more than one scoreboard, let us know what order the boards should appear on your game page. We won’t be able to change the order once your game and scoreboards are live.

Your game can have as many scoreboards as you would like, keeping track of various statistics. You can also choose which scoreboards will appear on your game page.

Adding scoreboard support after game has released

We can help with adding scoreboard support after your game has released on Catalog. To do this, we’ll need to create a new test game and test bundle id (eg. “com.studioname.gamenametest”) in our backend. Doing so will allow you to test the feature before it goes live to owners of the game.

Once you’re ready to release the scoreboard, you can email us so that we can add the new scoreboard to the live game and upload the new build. To send us a new build, you can follow the instructions in Managing Your Game After Release.

Daily scoreboards

Daily scoreboards will reset scores every day at midnight (12AM) GMT. If you would like to create a daily scoreboard, let us know and we’ll be able to enable this feature for a specific board.

Scoreboards and caching

The Scoreboards API will always try to retrieve the latest score or scores over Wi-Fi. In the case that network connectivity is not available, it will retrieve the score or scores from the local cache, if available.

Scoreboard performance

Because it can take a while to retrieve scores via Wi-Fi (sometimes 10 seconds or more on device), you could consider pre-fetching high scores if they are an important part of your game experience. (Note that you may be impacting performance of your game in other ways during the fetch period. Depending on your desired game experience, that delay may be more or less acceptable than the one users will encounter if you fetch only on-demand.)

Testing the Scoreboard API

On the Simulator

  • Your Simulator will need to be registered (associated with a user account). If it is not, an error will result upon calling a Scoreboard API. Scoreboard APIs typically return data that only make sense in the context of the user that is requesting the data. Scores posted from the Simulator will not show up on device and vice versa.

  • To ensure that the Simulator is registered to your user account, make sure to click the “Register” button after the page opens in your browser.

On a Playdate

  • IMPORTANT: Make sure to copy your game to your device over USB rather than via the wireless “Sideload” functionality. (Wireless sideload alters the game’s bundle ID, meaning your game will not match up with your registered scoreboards.)

  • Scores posted from device will not show up on the Simulator and vice versa.

Clearing scores after Testing

Email us and someone will be able to help clear the scores from your scoreboard!

Lua API reference

To use playdate.scoreboards, you must define a valid bundle ID in your PDX metadata. Scoreboards must be created on the Playdate servers.

playdate.scoreboards provides an interface to manage global high scores.

There is an on-device scoreboard cache which keeps track of most recent high scores, and keeps new scores for later submission.

Cacheable results are rerturned with a lastUpdated field, containing the timestamp of the last update represented as the number of seconds since Playdate epoch.

Callbacks are of the form:

scoreboardsCallback(status, result)

where status contains a code field specifying OK or ERROR:

{
	code = "ERROR",
	message = "Some error message"
}

playdate.scoreboards.getScoreboards(callback)

Invokes the given callback with a list of the registered scoreboards. (Note that if you already know the string ID for the scoreboard you want to query, this call is unnecessary.)

{
	lastUpdated = 649972900,
	boards = [
		{
			boardID = "highscores",
			name = "High Scores"
		},
		{
			boardID = "lowscores",
			name = "Low Scores"
		}
	]
}
  • callback: Callback to invoke with the results.

playdate.scoreboards.getScores(boardID, callback)

Invokes the given callback with a list of the top scores on the given board. (Typically ten scores or fewer.) If the current player is not in the top scores, their highest score is given as the last result.

Usernames for players are between 3-20 characters.

{
	lastUpdated = 649972900,
	scores = [
		{
			rank = 1,
			player = "mario",
			value = 100
		},
		{
			rank = 2,
			player = "luigi",
			value = 20
		}
	]
}
  • boardID: ID of the board to be queried.
  • callback: Callback to be invoked with the results.

playdate.scoreboards.addScore(boardID, value, callback)

Adds a new score to the specified board. Invokes the given callback with the resulting rank for the given value.

If Wi-Fi is not available, the outgoing value will be queued on device and sent to the server on a later attempt. In the case that it is added to the outgoing queue, the result will not specify a rank.

{
	rank = 30,
	player = "mario",
	value = 173
}
  • boardID: ID of the board.
  • value: Integer value to post on the board (positive integers only).
  • callback: Callback to invoke with the results.

playdate.scoreboards.getPersonalBest(boardID, callback)

Gets the player’s personal best score. Invokes the given callback with the score.

This will only operate on locally stored scores. In the event that there is no available high score for this player, the callback will be invoked with nil.

{
	rank = 7,
	player = "wario",
	value = 92
}

C API reference

Note that registered callbacks are responsible for freeing all scores and scoreboard data through the appropriate free functions documented below.

PDScore

typedef struct {
	uint32_t rank;
	uint32 t value:
	char *player;
} PDScore;
  • rank: The rank of this score in the scoreboard.
  • value: The actual score (positive integers only).
  • player: The name of the player who got this score (usernames are between 3-20 characters).

PDScoresList

typedef struct {
	char *boardID;
	unsigned int count;
	uint32_t lastUpdated;
	unsigned int playerIncluded;
	unsigned int limit;
	PDScore *scores;
} PDScoresList;
  • boardID: The ID string of the board.
  • count: The number of scores in the scores array.
  • lastUpdated: Timestamp of when we last updated these scores on device.
  • playerincluded: NYI
  • limit: NYI
  • scores: An array of scores, with count entries.

PDBoard

typedef struct {
	char *boardID;
	char *name:
} PDBoard;
  • boardID: The ID string of the board.
  • name: The friendly name of the board.

PDBoardsList

typedef struct {
	unsigned int count;
	uint32_t lastUpdated;
	PDBoard *boards;
} PDBoardsList;
  • count: The number of boards in the boards array.
  • lastUpdated: Timestamp of when we last updated this list on device.
  • boards: An array of scores, with count entries.

Callback Functions

typedef void (*AddScoreCallback) (PDScore *score, const char *errorMessage);
typedef void (*PersonalBestCallback) (PDScore *score, const char *errorMessage);
typedef void (*BoardsListCallback) (PDBoardsList *boards, const char *errorMessage);
typedef void (*ScoresCallback) (PDScoresList *scores, const char *errorMessage);

int playdate->scoreboads->addScore(const char *boardID, uint32_t value AddScoreCallback callback)

Adds a score to the specified board. If Wi-Fi is unavailable, adds it to a local outgoing cache. Invokes the callback with the resulting score and rank if Wi-Fi is available.

int playdate->scoreboards->getPersonalBest(const char *boardID, PersonalBestCallback callback)

Get the local player’s top score from the specified scoreboard. The score is returned through the provided callback. If Wi-Fi is unavailable, the player’s best score may be fetched from a local cache. If there is no personal best on the given board, the returned score is NULL.

void playdate->scoreboards->freeScore(PDScore *score)

Free a score struct that was provided to a callback.

int playdate->scoreboards->getScoreboards(BoardsListCallback callback)

Get the list of scoreboards available to this game. The list is returned through the provided callback. If Wi-Fi is unavailable, the list may be fetched from a local cache.

void playdate->scoreboards->freeBoardsList(PDBoardsList *boardsList)

Free a list of scoreboards.

int playdate-scoreboards-›getScores(const char *boardId, ScoresCallback callback)

Get the top scores for the specified board. (Typically ten or fewer.) The list of scores is returned through the provided callback. The list of scores will always contain the local player if they have any scores on the board. If Wi-Fi is unavailable, the list may be fetched from a local cache.

void playdate->scoreboards->freeScoresList(PDScoresList *scoresList)

Free a list of scores.

If you didn't find an answer above, contact us