Leaderboard Service¶
Using the iFun Engine Leaderboard, you can easily implement various types of ranking. Also, by combining the 2 dimensions described below, you can have multiple ranking types within a single game.
Competing group dimension
Social: particular group such as friend list, guild, etc.
All players
Competing period dimension
Daily
Weekly
All-time
For example, the supporting following rankings are possible by combining the two dimensions above.
Ranking by weekly highest score within friends
Ranking by all-time high score of all users
Ranking by daily score between guilds
Ranking by daily activity score between guild members
iFun Engine-Leaderboard Agent¶
As with authentication and billing, ranking is also structured as an agent in iFun Engine.
Installation¶
When developing a game server with iFun Engine, you can set use_leaderboard
to false
as explained here to work in test mode.
You can install later if you are evaluating or in the early stages of
development and don’t need accurate ranking storage and calculation.
Install the funapi auto-configuration package as explained here and install with the following commands.
$ sudo apt-get update
$ sudo apt-get install funapi-leaderboard1
Modify to enabled=1
in the file opened with the following command.
$ sudo vim /etc/default/funapi-leaderboard
Start the service with the following command. (The log is created in
/var/log/funapi/funapi-leaderboard1/
)
Before starting the service, see below to configure the database
information. If the database configuration is incorrect, the service
will not start.
$ sudo service funapi-leaderboard1 start
Configuration¶
Open the configuration file as below and modify the appropriate values.
$ sudo vim /usr/share/funapi-leaderboard/manifests/MANIFEST.json
Usage¶
You can either use the provided iFun Engine API (if developing the game server with iFun Engine) or the independent HTTP Interface (RESTful API). Refer to the following sections. The HTTP Interface will be provided in the future.
After installing the agent, you need to configure according to your tastes. This will be through MANIFEST.json as explained in the next section.
MANIFEST.json Configuration¶
Configure the iFun Engine-Leaderboard Agent by referring to here and the description below.
Component name: LeaderboardClient
Arguments
use_leaderboard
: Set astrue
orfalse
. Iffalse
, the ranking feature is bypassed and all ranking related requests will be responded with dummy values. This is useful for local testing environments.remote_leaderboard_ip_address
: Set the IP address of funapi- Leaderboard. The default value is used if not set.remote_leaderboard_port
: Set the port of funapi-leaderboard. The default value is used if not set.reset_on
: Set the ranking reset period. Values of the form “7am daily” means daily reset, “7am Monday weekly” means weekly reset, and “7am 4 monthly” means monthly reset. Keep the form of the strings, but replace the numbers and day of the week in 7am, Monday, and 4 as needed.
Example¶
Score Update¶
This is an example to update the score. Both synchronous and asynchronous methods are available.
Synchronous method¶
#include <funapi.h>
using namespace fun;
// Set the competing group.
// iFun Engine does not enforce the competing group name.
// The game developer can use any name to distinguish each ranking.
const char *kPlayerGameScore = "player_game"; // Ranking between players
// const char *kGuildGameScore = "guild_game"; // Ranking between guilds
// We assume a Facebook game as in the previous examples.
// Of course, the authentication method isn't really relevant.
void example(const string &facebook_id, int score) {
// Create a raking update request message.
ScoreSubmissionRequest request(
kPlayerGameScore, "Facebook", facebook_id, score);
ScoreSubmissionResponse response;
// Call the synchronized version of the ranking update function.
if (not SubmitScoreSync(request, &response)) {
// system error
LOG(ERROR) << "leaderboard system error";
return;
}
// Handle the result accordingly.
switch (response) {
case kNewRecord: {
// New all-time record!
} case kNewRecordWeekly: {
// New weekly record.
} case kNewRecordDaily: {
// New daily record.
break;
} case kNone: {
// no update
break;
} default: {
BOOST_ASSERT(false);
}
}
}
Asynchronous method¶
As with authentication and billing, asynchronous score updates can be
made by simply changing SubmitScoreSync()
to SubmitScore()
.
#include <funapi.h>
using namespace fun;
// Set the competing group.
// iFun Engine does not enforce the competing group name.
// The game developer can use any name to distinguish each ranking.
const char *kPlayerGameScore = "player_game";
// const char *kGuildGameScore = "guild_game";
// The callback function to be called after the score update.
void OnScoreSubmitted(
const ScoreSubmissionRequest &request,
const ScoreSubmissionResponse &response,
const bool &error) {
if (error) {
// system error
LOG(ERROR) << "leaderboard system error";
return;
}
switch (response) {
case kNewRecord: {
// all time new record
} case kNewRecordWeekly: {
// weekly new record
} case kNewRecordDaily: {
// daily new record
break;
} case kNone: {
// no update
break;
} default: {
BOOST_ASSERT(false);
}
}
}
// We assume a Facebook game as in the previous examples.
// Of course, the authentication method isn't really relevant.
void example(const string &facebook_id, int score) {
ScoreSubmissionRequest request(kPlayerGameScore, "Facebook", facebook_id, score);
ScoreSubmissionResponseHandler callback = OnScoreSubmitted;
// Start asynchronous processing.
SubmitScore(request, callback);
}
Public Ranking¶
This is an example to query the weekly top 10 scores of all players. (The commented code is an example for querying the 5 users ranked above and below “testuser” for today.)
Synchronized method¶
#include <funapi.h>
using namespace fun;
// Set the competing group.
// iFun Engine does not enforce the competing group name.
// The game developer can use any name to distinguish each ranking.
const char *kPlayerGameScore = "player_game";
void example() {
// Query the weekly ranking for the corresponding competing group.
// Grab the 0th to 9th users from the top.
LeaderboardQueryRequest request(
kPlayerGameScore, kWeekly, LeaderboardRange(LeaderboardRange::kFromTop, 0, 9));
// To grab the nearby rankings of specific player, do as the following.
// string service_provider = "Facebook"; // service provider
// string id = "testuser"; // user id in service provider
// LeaderboardQueryRequest request(
// kPlayerGameScore, service_provider, id, kDaily,
// LeaderboardRange(LeaderboardRange::kNearBy, -5, 5));
LeaderboardQueryResponse response;
// Call the synchronized method.
if (not GetLeaderboardSync(request, &response)) {
// system error
LOG(ERROR) << "leaderboard system error";
return;
}
// Print the fetched rankings.
for (int i = 0; i < response.size(); ++i) {
LOG(INFO) << "# " << response[i].rank << " - "
<< response[i].score << " - "
<< response[i].player_account.id();
}
}
Asynchronous method¶
#include <funapi.h>
using namespace fun;
// Set the competing group.
// iFun Engine does not enforce the competing group name.
// The game developer can use any name to distinguish each ranking.
const char *kPlayerGameScore = "player_game";
// Define the callback function to be called after fetching the rankings.
void OnResponse(
const LeaderboardQueryRequest &request,
const LeaderboardQueryResponse &response,
const bool &error) {
if (error) {
// system error
LOG(ERROR) << "leaderboard system error";
return;
}
for (int i = 0; i < response.size(); ++i) {
LOG(INFO) << "# " << response[i].rank << " - "
<< response[i].score << " - "
<< response[i].player_account.id();
}
}
void example() {
// Get the weekly ranking for the corresponding competing group.
// Grab the 0th to 9th users from the top.
LeaderboardQueryRequest request(kPlayerGameScore, kWeekly,
LeaderboardRange(LeaderboardRange::kFromTop, 0, 9));
// To grab the nearby rankings of specific player, do as the following.
// string service_provider = "Facebook"; // service provider
// string id = "testuser"; // user id in service provider
// LeaderboardQueryRequest request(
// kPlayerGameScore, service_provider, id, kDaily,
// LeaderboardRange(LeaderboardRange::kNearBy, -5, 5));
LeaderboardQueryResponseHandler callback = OnResponse;
// Start the asynchronous method.
GetLeaderboard(request, callback);
}
Social Ranking¶
The example below is for querying the weekly ranking of all friends of Facebook user “testuser”. If you see the commented out code in the example, you’ll see that you can also query last weeks rankings for the friends of “testuser”. In the example, we use the friend list; to fetch the friend list, refer to here.
Synchronous version¶
Asynchronous version¶
See here for fetching the friend list.