25. 内容支持Part 1: Leaderboard(排行榜)

Leaderboard服务中存在如下所示的 竞争群组轴竞争时间轴

  • 竞争群组轴

    • 社交: 好友列表、公会等特定群组

    • 所有玩家

  • 竞争时间轴

    • 每天

    • 每周

    • 所有

将这两个轴组合在一起,即可在一个游戏中构建多种不同的排行榜。

竞争群组轴和竞争时间轴的组合示例
  • 好友每周最高积分榜

  • 所有用户历史最高积分榜

  • 公会每周积分榜

  • 公会成员每日活动积分榜

25.1. iFun Leaderboard

iFun引擎使用名为 iFun Leaderboard 的程序,作为专门负责leaderboard的agent。 游戏服务器向iFun Leaderboard发送更新积分、查询排行榜等请求,iFun Leaderboard将实际执行这些任务。

Note

iFun引擎之所以使用单独的leaderboard agent是为了不影响游戏服务器,以便能够添加或更改新的结算方式。

同时,使用agent还可以使非游戏服务器的其他服务器通过agent的REST API来方便使用ranking相关服务。

25.1.1. 安装方法

Tip

游戏服务器端Leaderboard设置参数 的``use_leaderboard`` 设置为 false ,游戏服务器就会以对所有leaderboard请求进行dummy处理的测试模式来运行。该设置在开发初期阶段十分有用,此时无需安装iFun Leaderboard。

Note

leaderbaord为了处理cache,使用了Redis;为了保存排行榜,使用了 MySQL Server 。Redis需为2.8.4以上,MySQL server需为5.5以上。

25.1.1.1. Ubuntu环境

$ sudo apt-get update
$ sudo apt-get install funapi-leaderboard1 redis-server mysql-server

25.1.1.2. CentOS环境

$ sudo yum install funapi-leaderboard1 redis mysql-server
$ sudo systemctl enable funapi-leaderboard

25.1.2. 运行方法

25.1.2.1. Ubuntu 14.04或Centos 6环境下

打开 /etc/default/funapi-leaderboard 文件,并修改为 enabled=1

然后执行以下命令。

$ sudo service funapi-leaderboard start

25.1.2.2. Ubuntu 16.04或Centos 7环境下

执行以下命令。

$ sudo systemctl enable funapi-leaderboard
$ sudo systemctl start funapi-leaderboard

25.1.3. 查看任务

25.1.3.1. Ubuntu 14.04或Centos 6环境下

$ sudo service funapi-leaderboard status

25.1.3.2. Ubuntu 16.04或Centos 7环境下

$ sudo systemctl status funapi-leaderboard

25.1.3.3. Log文件

/var/log/funapi/funapi-leaderboard/ 中生成日志文件。

25.1.4. iFun Leaderboard设置方法(MANIFEST.json)

Note

该项目是iFun Leaderboard自身的设置内容。使用iFun Leaderboard设置游戏服务器时,请参考 游戏服务器端Leaderboard设置参数

iFun Leaderboard也是通过iFun引擎编写的程序。 因此,iFun Leaderboard也可以通过 MANIFEST.json 更改设置值。 iFun Leaderboard的MANIFEST.json位于 /usr/share/funapi-leaderboard/default/manifests/MANIFEST.json

可以指定如下设置值。

设置网络

  • server_tcp_port: 指定iFun引擎游戏服务器与iFun Leaderboard通信时的TCP port编号。(type=uint16, default=12820)

设置用于保存排行榜的MySQL

  • mysql_server_url: 输入保存排行榜信息的DB服务器IP地址和端口。(type=string, default=”tcp://127.0.0.1:3306”)

  • mysql_id: 输入保存排行榜信息的DB用户ID。(type=string, default=”funapileaderboard1”)

  • mysql_pw: 输入保存排行榜信息的DB用户密码。(type=string, default=”qlffj1!!”)

  • mysql_db_name: 输入保存排行榜信息的DB名。(type=string, default=”funapi_leaderboard1”)

  • mysql_db_connection_count: iFun Leaderboard和MySQL server通信时使用的connection pool size。(type=uint16, default=1)

  • mysql_db_character_set: 랭킹 정보가 저장되는 DB 에 적용할 character set 을 입력합니다. (type=string, default=”utf8”)

  • mysql_local_account_column_length: 랭킹 정보가 저장되는 DB 테이블의 local_account 컬럼의 길이를 입력합니다. (type=uint64, default=50)

  • leaderboard_use_db_stored_procedure: Mysql stored procedure 사용 여부를 입력합니다. (type=bool, default=true)

  • leaderboard_use_db_auto_schema_generation: 리더보드 서버를 실행할 때 DB 에 스키마를 자동으로 생성할 지 여부를 입력합니다. (type=bool, default=true)

  • export_db_schema_to_file: 지정된 경로에 DB 스키마 생성 스크립트를 저장하고 종료합니다. 단, leaderboard_use_db_auto_schema_generation 은 false 로 입력해야 합니다. (type=string, default=””)

设置用于保存排行榜的Redis

为对排行榜进行caching,iFun Leaderboard会使用Redis。Redis的设置直接运用iFun引擎的Redis会话。因此,须参考 Redis 기능 설정 파라미터 来输入Redis信息。

Important

由于是重新运用已经存在的Redis设置,所以与其他设置不同,Redis包含在dependency项目下。

设置Leaderboard

  • reset_schedules: 可以调整排行榜重置时间表。它是JSON object的类型,按如下形式记述。

    "reset_schedules": [
      {
        "leaderboard_id": String,
        "period": String
        "interval": Integer,
        "starts": String,
        "ends": String
      },
      ...
    ]
    
    • leaderboard_id: 输入对排行榜进行区分的名字。

    • period: 输入排行榜重置周期的单位。目前可以是 "day""week"

    • interval: 输入重置周期。根据已在period中定义的单位输入。例如,若period为day,interval为1,那么排行榜就是每天进行一次重置的每日排行榜。若period为week,interval为2,那么排行榜就是每2周进行一次重置的2周排行榜。

    • starts: 以 “2015-04-30 13:00:00” 的格式输入排行榜定期重置起始日期和时间。

    • ends: 以 “2020-12-31 23:59:59” 的格式输入排行榜定期重置结束日期和时间。

Tip

若更新代理,原来的MANIFEST.json将被覆盖。为了防止该问题,可以按照 临时重写MANIFEST.json 中的介绍,使用override文件。

/etc/funapi-leaderboard/MANIFEST.override.json:

{
  "override": {
    "FunapiLeaderboardServer": {
      "mysql_server_url": "tcp://10.10.10.10:36060",
      "mysql_id": "leaderboard",
      "mysql_pw": "leaderboard",
      ...
    },
    "Redis": {
      "enable_redis": true,
      "redis_mode": "redis",
      "redis_servers": {
        "": {
          "address": "127.0.0.1:6379",
          "auth_pass": ""
        }
      },
      ...
    }
    ...
  }
}

25.1.5. 设置服务器重置时间表

iFun Leaderboard agent可按所下所示,以特定周期重置排行榜。

排行榜的重置时间表可通过 iFun Leaderboard设置方法(MANIFEST.json)reset_schedules 注册或修改。排行榜重置时间表以 Leaderboard代理在MANIFEST中输入的 reset_schedules 为基础,自行 安排时间表,其运行方式如下。

  • 若仅注册每日排行榜重置时间表,则仅重置每日排行榜。

  • 若仅注册每周排行榜重置时间表,则仅重置每周排行榜。

  • 若每日、每周排行榜注册重置时间表均已注册,则两个排行榜分别单独运行。

25.1.5.1. 注册重置时间表

示例:

假设用于保存用户排行榜的leaderboard Id为 player_game_score ,用于保存公会排行榜的leaderboard ID为 guild_game_score , 我们试着对 用户每日排行榜 , 用户每周排行榜 , 公会2周排行榜 等3个排行榜注册重置时间表。

下面是iFun Leaderboard MANIFEST.json文件的部分内容。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
  ...
  "arguments": {
    ...
    "reset_schedules": [
      {
        "leaderboard_id": "player_game_score",
        "period": "day",
        "interval": 1,
        "starts": "2015-01-01 00:00:00",
        "ends": "2020-12-31 23:59:59"
      },
      {
        "leaderboard_id": "player_game_score",
        "period": "week",
        "interval": 1,
        "starts": "2015-01-01 00:00:00",
        "ends": "2020-12-31 23:59:59"
      },
      {
        "leaderboard_id": "guild_game",
        "period": "week",
        "interval": 2,
        "starts": "2015-05-01 00:00:00",
        "ends": "2020-12-31 23:59:59"
      }
    ]
  }
}

Note

由于2015年1月1日为周四,所以第二个重置时间表为每周四重置排行榜的时间表。与此类似,由于2015年5月1日为周五,所以第三个重置时间表为每周五重置排行榜。

25.1.5.2. 修改重置时间表

和注册重置时间表一样,修改重置时间表也通过MANIFEST.json的 reset_schedules 进行。 因此,只要在 reset_schedules 中变更想要修改的项目即可。

25.1.6. (高级)直接删除或修复排行榜数据

25.1.6.1. iFun Leaderboard保存在MySQL中的数据

在MySQL中通过如下模式以创建table来保存排行榜数据。

{leaderboard_id}_{timespan}

例如,将 leaderboard_id 指定为player_game,若积分更新,则将生成如下SQL table。

  • player_game_alltime

  • player_game_daily

  • player_game_weekly

  • player_game_lastweek

  • player_game_yesterday

Note

lastweekyesterday 在重置时间表启动后,排行榜得到初始化时生成。

25.1.6.2. iFun Leaderboard保存在Redis中的数据

在Redis 中通过如下模式以指定key来保存排行榜数据。

leaderboard:{leaderboard_id}:{timespan}
leaderboard:{leaderboard_id}:{timespan}:dense
leaderboard:{leaderboard_id}:{timespan}:timestamp
leaderboard:{leaderboard_id}:{player_id}:friends

Note

leaderboard:{leaderboard_id}:{player_id}:friends 是为了处理好友排行榜而生成的,待处理结束后将被删除。

例如,将 leaderboard_id 指定为player_game,若积分更新,Redis中将生成如下key。

默认keys:

  • leaderboard:player_game:alltime

  • leaderboard:player_game:daily

  • leaderboard:player_game:weekly

  • leaderboard:player_game:lastweek

  • leaderboard:player_game:yesterday

dense keys:

  • leaderboard:player_game:alltime:dense

  • leaderboard:player_game:daily:dense

  • leaderboard:player_game:weekly:dense

  • leaderboard:player_game:lastweek:dense

  • leaderboard:player_game:yesterday:dense

timestamp keys:

  • leaderboard:player_game:alltime:timestamp

  • leaderboard:player_game:daily:timestamp

  • leaderboard:player_game:weekly:timestamp

  • leaderboard:player_game:lastweek:timestamp

  • leaderboard:player_game:yesterday:timestamp

Note

lastweekyesterday 在重置时间表启动后,排行榜得到初始化时生成。

25.1.6.3. 删除排行榜数据

为了删除排行榜数据,须要将存在于MySQL和Redis中的相关数据全部删除。

25.1.6.3.1. 在MySQL中删除排行榜数据

使用 truncate tabledrop table 命令删除 iFun Leaderboard保存在MySQL中的数据 中提到的数据表。

例如,假设 leaderboard_id 为player_game时,代码如下所示。

mysql> truncate table player_game_alltime
mysql> truncate table player_game_daily
mysql> truncate table player_game_weekly
mysql> truncate table player_game_lastweek
mysql> truncate table player_game_yesterday

또는

mysql> drop table player_game_alltime
mysql> drop table player_game_daily
mysql> drop table player_game_weekly
mysql> drop table player_game_lastweek
mysql> drop table player_game_yesterday
25.1.6.3.2. 在Redis中删除排行榜数据

利用 del 命令删除 iFun Leaderboard保存在Redis中的数据 中提到的key。

例如,假设 leaderboard_id 为player_game时,代码如下所示。

127.0.0.1:6379> del leaderboard:player_game:alltime
127.0.0.1:6379> del leaderboard:player_game:daily
127.0.0.1:6379> del leaderboard:player_game:weekly
127.0.0.1:6379> del leaderboard:player_game:lastweek
127.0.0.1:6379> del leaderboard:player_game:yesterday

127.0.0.1:6379> del leaderboard:player_game:alltime:timestamp
127.0.0.1:6379> del leaderboard:player_game:daily:timestamp
127.0.0.1:6379> del leaderboard:player_game:weekly:timestamp
127.0.0.1:6379> del leaderboard:player_game:lastweek:timestamp
127.0.0.1:6379> del leaderboard:player_game:yesterday:timestamp

127.0.0.1:6379> del leaderboard:player_game:alltime:dense
127.0.0.1:6379> del leaderboard:player_game:daily:dense
127.0.0.1:6379> del leaderboard:player_game:weekly:dense
127.0.0.1:6379> del leaderboard:player_game:lastweek:dense
127.0.0.1:6379> del leaderboard:player_game:yesterday:dense

Tip

若存在Leaderboard专用Redis Server,则可以使用Redis命令 flushall 更加方便地数据删除。

127.0.0.1:6379> flushall

25.1.6.4. 在MySQL中通过Redis修复排行榜数据

若Redis server中数据已损坏,可通过修复模式运行iFun Leaderboard agent ,通过Redis来修复MySQL中保存的排行榜数据。

Tip

修复模式仅仅是在MySQL中用Redis复制数据,不会删除Redis存在的原数据。

运行Leaderboard代理修复模式时,按如下所示输入代码。

Ubuntu 14.04或Centos 6环境下

$ sudo service funapi-leaderboard stop
$ funapi-leaderboard-launcher --alsologtostderr --recover_leaderboard
$ sudo service funapi-leaderboard start

Ubuntu 16.04或Centos 7环境下

$ sudo systemctl stop funapi-leaderboard
$ funapi-leaderboard-launcher --alsologtostderr --recover_leaderboard
$ sudo systemctl start funapi-leaderboard

Important

运行修复模式时,一定要添加 –alsologtostderr选项。如运行时省略该选项,会输出让添加选项的日志 的同时结束运行。

若通过上述修复模式运行,会调取MySQL中存在的所有leaderboard table 数据来进行修复,但会询问是否进行修复。

$ funapi-leaderboard-launcher --alsologtostderr --recover_leaderboard
...
I1221 11:19:49.893380  9231 leaderboard.cc:714] Start recovery mode
I1221 11:19:50.894167  9231 leaderboard.cc:742] The recovery target leaderboard: player_game
I1221 11:19:50.894194  9231 leaderboard.cc:745] The leaderboard will be recovered ranking data from DB to Redis. Do you want to do this? (y, n)

是否进行修复是以leaderboard ID为单位进行确认的,而不是以table为单位。 例如,当使用名为 player_gameguild_game leaderboard ID时, MySQL中将存在如下数据表,并先确认是否对 player_game 进行修复后,将确认是否对 guild_game 进行修复。

mysql> show tables;
+-------------------------------+
| Tables_in_funapi_leaderboard1 |
+-------------------------------+
| player_game_alltime           |
| player_game_daily             |
| player_game_lastweek          |
| player_game_weekly            |
| player_game_yesterday         |
| guild_game_alltime            |
| guild_game_daily              |
| guild_game_lastweek           |
| guild_game_weekly             |
| guild_game_yesterday          |
+-------------------------------+

Tip

为了强制进行修复,而不是询问是否修复,可以添加 --force_leaderboard_recovery 选项。 当添加了该选项时,有可能遗漏 --alsologtostderr ,但为了查看修复的进展情况,最好添加该选项。

$ funapi-leaderboard-launcher --force_leaderboard_recovery --alsologtostderr

25.2. 示例: 查询排行榜

下面我们通过示例来了解查询排行榜的方法。 其中,竞争群组的名字我们使用 player_game

Tip

与下面的函数有关的更具体的内容请参考 API文件

其中,用于指定查询范围的 LeaderboardRange::Type 须根据设置值进行如下使用。

Type

设置begin和end

kAll

begin和end须设置为0。

kFromTop

begin须为0以上,end须大于或等于begin。

kNearby

begin可以小于0,end须大于或等于begin。

25.2.1. 查询每周全部排名

25.2.1.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const char *kPlayerGameScore = "player_game";


void example() {
  LeaderboardQueryRequest request(
      kPlayerGameScore,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kAll, 0, 0),  // 전체 랭킹을 조회
      LeaderboardQueryRequest::kOrdinal);  // rank 값으로 1, 2, 3, 4 를 사용

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static string kPlayerGameScore = "player_game";

public static void example()
{
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kAll, 0, 0),  // 전체 랭킹을 조회
    Leaderboard.RankingType.kOrdinal);  // rank 값으로 1, 2, 3, 4 를 사용

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync (request, out response))
  {
    Log.Error ("leaderboard system error");
    return;
  }

  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

25.2.1.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const char *kPlayerGameScore = "player_game";


void OnResponse(
    const LeaderboardQueryRequest &request,
    const LeaderboardQueryResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}


void example() {
  LeaderboardQueryRequest request(
      kPlayerGameScore,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kAll, 0, 0),  // 전체 랭킹 조회
      LeaderboardQueryRequest::kOrdinal);  // rank 값으로 1, 2, 3, 4 를 사용

  LeaderboardQueryResponseHandler handler = OnResponse;
  GetLeaderboard(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static string kPlayerGameScore = "player_game";

public static void OnResponse(Leaderboard.QueryRequest request,
                              Leaderboard.QueryResponse response,
                              bool error)
{
  if (error) {
    Log.Error ("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

public static void example()
{
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kAll, 0, 0),  // 전체 랭킹 조회
    Leaderboard.RankingType.kOrdinal);  // rank 값으로 1, 2, 3, 4 사용

  Leaderboard.GetLeaderboard(request, OnResponse);
}

25.2.2. 查询每周TOP10排名

25.2.2.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const char *kPlayerGameScore = "player_game";


void example() {
  LeaderboardQueryRequest request(
      kPlayerGameScore,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kFromTop, 0, 9),  // Top 10 을 조회
      LeaderboardQueryRequest::kStdCompetition);  // 1, 2, 2, 4 식으로 동점자를 처리합니다.

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static string kPlayerGameScore = "player_game";

public static void example()
{
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kFromTop, 0, 9),  // Top 10 을 조회
    Leaderboard.RankingType.kStdCompetition);  // 1, 2, 2, 4 식으로 동점자를 처리

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync (request, out response))
  {
    Log.Error ("leaderboard system error");
    return;
  }

  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

25.2.2.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const char *kPlayerGameScore = "player_game";


void OnResponse(
    const LeaderboardQueryRequest &request,
    const LeaderboardQueryResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}


void example() {
  LeaderboardQueryRequest request(
      kPlayerGameScore,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kFromTop, 0, 9),  // Top 10 을 조회
      LeaderboardQueryRequest::kStdCompetition);  // 1, 2, 2, 4 식으로 동점자 처리

  LeaderboardQueryResponseHandler handler = OnResponse;
  GetLeaderboard(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
static string kPlayerGameScore = "player_game";

public static void OnResponse(Leaderboard.QueryRequest request,
                              Leaderboard.QueryResponse response,
                              bool error)
{
  if (error) {
    Log.Error ("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

public static void example()
{
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kFromTop, 0, 9),  // Top 10 조회
    Leaderboard.RankingType.kStdCompetition);  // 1, 2, 2, 4 식으로 동점자 처리

  Leaderboard.QueryResponse response;
  Leaderboard.GetLeaderboard(request, OnResponse);
}

25.2.3. 查询自身所在排名的周围玩家排名

下面是查询用户前后5名玩家的示例。 现在我们试着查询其中的Facebook用户群组内的排行榜。

25.2.3.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const char *kPlayerGameScore = "player_game";


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  LeaderboardQueryRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kNearBy, -5, 5),  // 위 아래 5순위.
      LeaderboardQueryRequest::kDense);  // 동점자가 있을 시 1, 2, 2, 3 형태로 처리

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static string kPlayerGameScore = "player_game";

public static void example()
{
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    service_provider,
    player_id,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kNearBy, -5, 5),  // 위 아래 5 순위.
    Leaderboard.RankingType.kDense);  // 동점자가 있을 시, 1, 2, 2, 3 형태로 처리

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync (request, out response))
  {
    Log.Error("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

25.2.3.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const char *kPlayerGameScore = "player_game";


void OnResponse(
    const LeaderboardQueryRequest &request,
    const LeaderboardQueryResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  LeaderboardQueryRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kNearBy, -5, 5),  // 위 아래 5순위.
      LeaderboardQueryRequest::kDense);  // 동점자를 1, 2, 2, 3 형태로 처리

  LeaderboardQueryResponseHandler handler = OnResponse;
  GetLeaderboard(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static string kPlayerGameScore = "player_game";

public static void OnResponse(Leaderboard.QueryRequest request,
                              Leaderboard.QueryResponse response,
                              bool error)
{
  if (error) {
    Log.Error ("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

public static void example()
{
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    service_provider,
    player_id,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kNearby, -5, 5),  // 위 아래 5순위.
    Leaderboard.RankingType.kDense);  // 동점자를 1, 2, 2, 3 형태로 처리

  Leaderboard.GetLeaderboard(request, OnResponse);
}

25.2.4. 查询自身排名

下面是查询用户自身排名的示例。 现在我们试着查询其中的Facebook用户群组内的排行榜。

25.2.4.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const char *kPlayerGameScore = "player_game";


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  // RankingType 은 입력하지 않았으므로 기본값인 kOrdinal 이 됩니다.
  LeaderboardQueryRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kNearBy, 0, 0));  // 자기 랭킹을 조회합니다.

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 을 사용했으로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static string kPlayerGameScore = "player_game";

public static void example()
{
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  // RankingType 은 입력하지 않았으므로 기본값인 kOrdinal 이 됩니다.
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    service_provider,
    player_id,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kNearby, 0, 0)  // 자기 랭킹 조회
  );

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync (request, out response))
  {
    Log.Error("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 을 사용했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

25.2.4.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const char *kPlayerGameScore = "player_game";


void OnResponse(
    const LeaderboardQueryRequest &request,
    const LeaderboardQueryResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 로 사용했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  // RankingType 은 입력하지 않았으므로 기본값인 kOrdinal 이 됩니다.
  LeaderboardQueryRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      kWeekly,
      LeaderboardRange(LeaderboardRange::kNearBy, 0, 0));  // 자기 랭킹을 조회합니다.

  LeaderboardQueryResponseHandler handler = OnResponse;
  GetLeaderboard(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using funapi;

static string kPlayerGameScore = "player_game";

public static void OnResponse(Leaderboard.QueryRequest request,
                              Leaderboard.QueryResponse response,
                              bool error)
{
  if (error) {
    Log.Error ("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 로 사용했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

public static void example()
{
  const string kPlayerGameScore = "player_game";

  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  // RankingType 은 입력하지 않았으므로 기본값인 kOrdinal 이 됩니다.
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    service_provider,
    player_id,
    Leaderboard.Timespan.kWeekly,
    new Leaderboard.Range (Leaderboard.RangeType.kNearby, 0, 0)  // 자기 랭킹 조회
  );

  Leaderboard.GetLeaderboard(request, OnResponse);
}

25.2.5. 查询好友排名

下面是查询Facebook好友排名的方法。 获取Facebook好友列表的方法请参考 示例: 提取Facebook好友

Tip

在下面的示例中,在创建LeaderboardQueryRequest时,若将kWeekly更改为kLastWeek,即可创建获取上周好友排行榜的请求。 与此类似,若更改为kYesterday,则可以创建获取上月好友排行榜的请求。

LeaderboardQueryRequest request(
    kPlayerGameScore, service_provider, player_id, friend_list, kLastWeek);

25.2.5.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const char *kPlayerGameScore = "player_game";


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  PlayerAccountVector friend_list = ...;  // 친구 리스트를 추출했다고 가정하겠습니다.

  // RankingType 은 입력하지 않았으므로 기본값인 kOrdinal 이 됩니다.
  LeaderboardQueryRequest request(
      kPlayerGameScore, service_provider, player_id, friend_list, kWeekly);

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 로 했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
static string kPlayerGameScore = "player_game";

public static void example()
{
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  List<PlayerAccount> friend_list = ...;  // 친구 목록을 추출했다고 가정하겠습니다.

  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    service_provider,
    player_id,
    friend_list,
    Leaderboard.Timespan.kWeekly);

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync (request, out response))
  {
    Log.Error("leaderboard system error");
    return;

  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 로 했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

25.2.5.2. 非同步版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const char *kPlayerGameScore = "player_game";

void OnResponse(
    const LeaderboardQueryRequest &request,
    const LeaderboardQueryResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  LOG(INFO) << "total player count: " << response.total_player_count;

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 로 했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  for (int i = 0; i < response.records.size(); ++i) {
    LOG(INFO) << "# " << response.records[i].rank << " - "
              << response.records[i].percentage << " - "
              << response.records[i].score << " - "
              << response.records[i].player_account.id();
  }
}


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  PlayerAccountVector friend_list = ...;  // 친구 목록을 추출했다고 가정하겠습니다.

  // RankingType 은 입력하지 않았으므로 기본값인 kOrdinal 이 됩니다.
  LeaderboardQueryRequest request(
      kPlayerGameScore, service_provider, player_id, friend_list, kWeekly);

  LeaderboardQueryResponseHandler handler = OnResponse;
  GetLeaderboard(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
static string kPlayerGameScore = "player_game";

public static void OnResponse(Leaderboard.QueryRequest request,
                              Leaderboard.QueryResponse response,
                              bool error)
{
  if (error) {
    Log.Error ("leaderboard system error");
    return;
  }

  Log.Info("total player count: {0}", response.TotalPlayerCount);

  // 랭킹 타입을 묵시적 기본값인 kOrdinal 로 했으므로 rank 값은 1, 2, 3, 4, ... 이 됩니다.
  foreach (Leaderboard.Record record in response.Records)
  {
    Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
              record.Rank, record.Percentage,
              record.Score, record.PlayerAccount.Id);
  }
}

public static void example()
{
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  List<PlayerAccount> friend_list = ...;  // 친구 목록을 추출했다고 가정하겠습니다.

  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
    kPlayerGameScore,
    service_provider,
    player_id,
    friend_list,
    Leaderboard.Timespan.kWeekly);

  Leaderboard.GetLeaderboard(request, OnResponse);
}

25.2.6. 同时查询多个排行榜

下面的示例是将上面查询的TOP10排名、自身所在排名的周围玩家排名、自身排名、好友排名的示例合到一起,通过一次性请求来查询多个不同排行榜的示例。

25.2.6.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
const char *kPlayerGameScore = "player_game";


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  // 한번에 여러 랭킹을 조회할 것이므로 Vector 를 만듭니다.
  LeaderboardQueryRequestVector requests;

  // 우선 TOP 10 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          kWeekly,
          LeaderboardRange(LeaderboardRange::kFromTop, 0, 9),
          LeaderboardQueryRequest::kStdCompetition));

  // 내 주변 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          kWeekly,
          LeaderboardRange(LeaderboardRange::kNearBy, -5, 5),
          LeaderboardQueryRequest::kDense));

  // 내 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          kWeekly,
          LeaderboardRange(LeaderboardRange::kNearBy, 0, 0));

  // 친구 목록은 가져왔다고 가정하겠습니다.
  PlayerAccountVector friend_list = ...;

  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          friend_list,
          kWeekly);

  // 랭킹을 조회합니다.
  LeaderboardQueryResponseVector responses;
  if (not GetLeaderboardSync(requests, &responses)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  // responses 를 하나씩 루프돌면서 얻어온 랭킹 결과를 출력합니다.
  BOOST_FOREACH(const LeaderboardQueryResponse &response, responses) {
    LOG(INFO) << "total player count: " << response.total_player_count;

    for (int i = 0; i < response.records.size(); ++i) {
      LOG(INFO) << "# " << response.records[i].rank << " - "
                << response.records[i].percentage << " - "
                << response.records[i].score << " - "
                << response.records[i].player_account.id();
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  static string kPlayerGameScore = "player_game";

  public static void example()
  {
    string service_provider = "Facebook"; // service provider
    string player_id = "testuser";        // player id in service provider

    List<Leaderboard.QueryRequest> requests = new List<Leaderboard.QueryRequest> ();

    // 우선 TOP 10 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
    requests.Add (new Leaderboard.QueryRequest(
        kPlayerGameScore,
        Leaderboard.Timespan.kWeekly,
        // 전체 랭킹을 조회합니다.
        new Leaderboard.Range (Leaderboard.RangeType.kFromTop, 0, 9),
        // 1224 랭킹 타입으로 동점자 순위를 처리합니다.
        Leaderboard.RankingType.kStdCompetition));

    // 내 주변 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
    requests.Add (new Leaderboard.QueryRequest(
        kPlayerGameScore,
        service_provider,
        player_id,
        Leaderboard.Timespan.kWeekly,
        // 위 아래 5명의 랭킹을 조회합니다.
        new Leaderboard.Range (Leaderboard.RangeType.kNearby, -5, 5),
        // 1223 랭킹 타입으로 동점자 순위를 처리합니다.
        Leaderboard.RankingType.kDense));

    // 내 랭킹을 조회하기 위한 요청자를 만들고 list 에 추가합니다.
    requests.Add (new Leaderboard.QueryRequest(
        kPlayerGameScore,
        service_provider,
        player_id,
        Leaderboard.Timespan.kWeekly,
        // 나의 랭킹을 조회합니다.
        new Leaderboard.Range (Leaderboard.RangeType.kNearby, 0, 0)));

    // 친구 목록은 가져왔다고 가정하겠습니다.
    List<PlayerAccount> friend_list = ...;

    requests.Add (new Leaderboard.QueryRequest(
        kPlayerGameScore,
        service_provider,
        player_id,
        friend_list,
        Leaderboard.Timespan.kWeekly));

    List<Leaderboard.QueryResponse> responses;

    // 랭킹을 조회합니다.
    if (!Leaderboard.GetLeaderboard (requests, out responses))
    {
      return;
    }

    foreach (Leaderboard.QueryResponse response in responses)
    {
      foreach (Leaderboard.Record record in response.Records)
      {
        Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
                  record.Rank, record.Percentage,
                  record.Score, record.PlayerAccount.Id);
      }
    }
  }

25.2.6.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
const char *kPlayerGameScore = "player_game";


void OnResponse(
    const LeaderboardQueryRequestVector &requests,
    const LeaderboardQueryResponseVector &responses,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  // responses 를 하나씩 루프돌면서 얻어온 랭킹 결과를 출력합니다.
  BOOST_FOREACH(const LeaderboardQueryResponse &response, responses) {
    LOG(INFO) << "total player count: " << response.total_player_count;

    for (int i = 0; i < response.records.size(); ++i) {
      LOG(INFO) << "# " << response.records[i].rank << " - "
                << response.records[i].percentage << " - "
                << response.records[i].score << " - "
                << response.records[i].player_account.id();
    }
  }
}


void example() {
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  LeaderboardQueryRequestVector requests;

  // 우선 TOP 10 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          kWeekly,
          LeaderboardRange(LeaderboardRange::kFromTop, 0, 9),
          LeaderboardQueryRequest::kStdCompetition));

  // 내 주변 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          kWeekly,
          LeaderboardRange(LeaderboardRange::kNearBy, -5, 5),
          LeaderboardQueryRequest::kDense));

  // 내 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          kWeekly,
          LeaderboardRange(LeaderboardRange::kNearBy, 0, 0));

  // 친구 목록은 가져왔다고 가정하겠습니다.
  PlayerAccountVector friend_list = ...;

  requests.push_back(
      LeaderboardQueryRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          friend_list,
          kWeekly);

  // 랭킹을 조회합니다.
  LeaderboardQueryResponseHandler2 handler = OnResponse;
  GetLeaderboard(requests, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
static string kPlayerGameScore = "player_game";

public static void OnResponse(
    List<Leaderboard.QueryRequest> requests,
    List<Leaderboard.QueryResponse> responses,
    bool error)
{
  if (error) {
    return;
  }

  foreach (Leaderboard.QueryResponse response in responses)
  {
    foreach (Leaderboard.Record record in response.Records)
    {
      Log.Info ("rank={0}, percentage={1}, score={2}, id={3}",
                record.Rank, record.Percentage,
                record.Score, record.PlayerAccount.Id);
    }
  }
}

public static void example()
{
  string service_provider = "Facebook"; // service provider
  string player_id = "testuser";        // player id in service provider

  List<Leaderboard.QueryRequest> requests = new List<Leaderboard.QueryRequest> ();

  // 우선 TOP 10 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.Add (new Leaderboard.QueryRequest(
      kPlayerGameScore,
      Leaderboard.Timespan.kWeekly,
      // 전체 랭킹을 조회합니다.
      new Leaderboard.Range (Leaderboard.RangeType.kFromTop, 0, 9),
      // 1224 랭킹 타입으로 동점자 순위를 처리합니다.
      Leaderboard.RankingType.kStdCompetition));

  // 내 주변 랭킹을 조회하기 위한 요청자를 만들고 vector 에 추가합니다.
  requests.Add (new Leaderboard.QueryRequest(
      kPlayerGameScore,
      service_provider,
      player_id,
      Leaderboard.Timespan.kWeekly,
      // 위 아래 5명의 랭킹을 조회합니다.
      new Leaderboard.Range (Leaderboard.RangeType.kNearby, -5, 5),
      // 1223 랭킹 타입으로 동점자 순위를 처리합니다.
      Leaderboard.RankingType.kDense));

  // 내 랭킹을 조회하기 위한 요청자를 만들고 list 에 추가합니다.
  requests.Add (new Leaderboard.QueryRequest(
      kPlayerGameScore,
      service_provider,
      player_id,
      Leaderboard.Timespan.kWeekly,
      // 나의 랭킹을 조회합니다.
      new Leaderboard.Range (Leaderboard.RangeType.kNearby, 0, 0)));

  // 친구 목록은 가져왔다고 가정하겠습니다.
  List<PlayerAccount> friend_list = ...;

  requests.Add (new Leaderboard.QueryRequest(
      kPlayerGameScore,
      service_provider,
      player_id,
      friend_list,
      Leaderboard.Timespan.kWeekly));

  // 랭킹을 조회합니다.
  Leaderboard.GetLeaderboard (requests, OnResponse);
}

25.3. 示例: 更新积分

更新积分的方法共有4种。

类型

说明

kHighScore

仅在既定积分为最高积分时更新。

kIncrement

让当前积分增加到既定积分。

kDecrement

让当前积分减少到既定积分。

kOverwriting

用既定积分覆盖当前积分。

下面通过示例来分析更新积分的方法。

25.3.1. 最高积分时更新

25.3.1.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const char *kPlayerGameScore = "player_game";

void example() {
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  ScoreSubmissionRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      score,
      ScoreSubmissionRequest::kHighScore);

  ScoreSubmissionResponse response;
  if (not SubmitScoreSync(request, &response)) {
    // system error
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  LOG(INFO) << "new score: " << response.new_score;

  // 결과값에 따라 대응합니다.
  switch (response.result) {
    case kNewRecord: {
      // 신기록이네요.
      break;
    }
    case kNewRecordWeekly: {
      // 주간 최고 기록입니다.
      break;
    }
    case kNewRecordDaily: {
      // 일간 최고 기록입니다.
      break;
    }
    case kNone: {
      // no update
      break;
    }
    default: {
      BOOST_ASSERT(false);
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
static string kPlayerGameScore = "player_game";

public void exmaple()
{
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  Leaderboard.ScoreSubmissionRequest request =
      new Leaderboard.ScoreSubmissionRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          score,
          Leaderboard.ScoreSubmissionType.kHighScore);

  Leaderboard.ScoreSubmissionResponse response;
  if (!Leaderboard.SubmitScoreSync (request, out response))
  {
    Log.Error ("leaderboard system error");
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  Log.Info ("new score: {0}", response.NewScore);

  // 결과값에 따라 대응합니다.
  switch (response.Result)
  {
    case Leaderboard.ScoreSubmissionResult.kNewRecord:
    {
      // 신기록이네요.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordWeekly:
    {
      // 주간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordDaily:
    {
      // 일간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNone:
    {
      // no update
      break;
    }
  }
}

25.3.1.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
const char *kPlayerGameScore = "player_game";

void OnScoreSubmitted(
    const ScoreSubmissionRequest &request,
    const ScoreSubmissionResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  LOG(INFO) << "new score: " << response.new_score;

  // 결과값에 따라 대응합니다.
  switch (response.result) {
    case kNewRecord: {
      // 신기록이네요.
      break;
    }
    case kNewRecordWeekly: {
      // 주간 최고 기록입니다.
      break;
    }
    case kNewRecordDaily: {
      // 일간 최고 기록입니다.
      break;
    }
    case kNone: {
      // no update
      break;
    }
    default: {
      BOOST_ASSERT(false);
    }
  }
}


void example() {
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  ScoreSubmissionRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      score,
      ScoreSubmissionRequest::kHighScore);

  ScoreSubmissionResponseHandler handler = OnScoreSubmitted;
  SubmitScore(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
string kPlayerGameScore = "player_game";

public static void OnScoreSubmitted(
    Leaderboard.ScoreSubmissionRequest request,
    Leaderboard.ScoreSubmissionResponse response,
    bool error)
{
  if (error)
  {
    Log.Error ("leaderboard system error");
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  Log.Info ("new score: {0}", response.NewScore);

  // 결과값에 따라 대응합니다.
  switch (response.Result)
  {
    case Leaderboard.ScoreSubmissionResult.kNewRecord:
    {
      // 신기록이네요.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordWeekly:
    {
      // 주간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordDaily:
    {
      // 일간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNone:
    {
      // no update
      break;
    }
  }
}

public static void example()
{
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  Leaderboard.ScoreSubmissionRequest request =
      new Leaderboard.ScoreSubmissionRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          score,
          Leaderboard.ScoreSubmissionType.kHighScore);

  Leaderboard.SubmitScore (request, OnScoresubmitted);
}

25.3.2. 积分更新后调取自身排名

下面我们来了解更新分数后同时调取自身排名的示例。

25.3.2.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const char *kPlayerGameScore = "player_game";

void example() {
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  ScoreSubmissionRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      score,
      LeaderboardQueryRequest::kOrdinal,
      kWeekly,
      ScoreSubmissionRequest::kHighScore);

  ScoreSubmissionResponse response;
  if (not SubmitScoreSync(request, &response)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  // 내 랭킹 정보도 함께 출력합니다.
  LOG(INFO) << "new score: " << response.new_score
            << ", total player count: " << response.total_player_count
            << ", my rank: " << response.rank
            << ", percentage: " << response.percentage;

  // 결과값에 따라 대응합니다.
  switch (response.result) {
    case kNewRecord: {
      // 신기록이네요.
      break;
    }
    case kNewRecordWeekly: {
      // 주간 최고 기록입니다.
      break;
    }
    case kNewRecordDaily: {
      // 일간 최고 기록입니다.
      break;
    }
    case kNone: {
      // no update
      break;
    }
    default: {
      BOOST_ASSERT(false);
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
static string kPlayerGameScore = "player_game";

public static void example()
{
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  Leaderboard.ScoreSubmissionRequest request =
      new Leaderboard.ScoreSubmissionRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          score,
      Leaderboard.RankingType.kOrdinal,
      Leaderboard.Timespan.kWeekly,
      Leaderboard.ScoreSubmissionType.kHighScore);

  Leaderboard.ScoreSubmissionResponse response;
  if (!Leaderboard.SubmitScoreSync(request, out response))
  {
    Log.Error ("leaderboard system error");
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  // 내 랭킹 정보도 함께 출력합니다.
  Log.Info (
      "new score: {0}, total player count: {1}, my rank: {2}, percentage: {3}",
      response.NewScore, response.TotalPlayerCount, response.Rank, response.Percentage);

  // 결과값에 따라 대응합니다.
  switch (response.Result)
  {
    case Leaderboard.ScoreSubmissionResult.kNewRecord:
    {
        // 신기록이네요.
        break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordWeekly:
    {
      // 주간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordDaily:
    {
      // 일간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNone:
    {
      // no update
      break;
    }
  }
}

25.3.2.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
const char *kPlayerGameScore = "player_game";

void OnScoreSubmitted(
    const ScoreSubmissionRequest &request,
    const ScoreSubmissionResponse &response,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  // 내 랭킹 정보도 함께 출력합니다.
  LOG(INFO) << "new score: " << response.new_score
            << ", total player count: " << response.total_player_count
            << ", my rank: " << response.rank
            << ", percentage: " << response.percentage;

  // 결과값에 따라 대응합니다.
  switch (response.result) {
    case kNewRecord: {
      // 신기록이네요.
      break;
    }
    case kNewRecordWeekly: {
      // 주간 최고 기록입니다.
      break;
    }
    case kNewRecordDaily: {
      // 일간 최고 기록입니다.
      break;
    }
    case kNone: {
      // no update
      break;
    }
    default: {
      BOOST_ASSERT(false);
    }
  }
}


void example() {
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  ScoreSubmissionRequest request(
      kPlayerGameScore,
      service_provider,
      player_id,
      score,
      LeaderboardQueryRequest::kOrdinal,
      kWeekly,
      ScoreSubmissionRequest::kHighScore);

  ScoreSubmissionResponseHandler handler = OnScoreSubmitted;
  SubmitScore(request, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
static string kPlayerGameScore = "player_game";

public static void OnScoreSubmitted(
    Leaderboard.ScoreSubmissionRequest request,
    Leaderboard.ScoreSubmissionResponse response,
    bool error)
{
  // kHighScore 인 경우 최고 점수 여부와 상관없이 입력한 score 와 동일합니다.
  // kIncrement, kDecrement 인 경우 증가, 감소된 점수입니다.
  // kOverwriting 인 경우 입력한 score 와 동일합니다.
  // 내 랭킹 정보도 함께 출력합니다.
  Log.Info (
      "new score: {0}, total player count: {1}, my rank: {2}, percentage: {3}",
      response.NewScore, response.TotalPlayerCount, response.Rank, response.Percentage);

  // 결과값에 따라 대응합니다.
  switch (response.Result)
  {
    case Leaderboard.ScoreSubmissionResult.kNewRecord:
    {
      // 신기록이네요.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordWeekly:
    {
      // 주간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNewRecordDaily:
    {
      // 일간 최고 기록입니다.
      break;
    }
    case Leaderboard.ScoreSubmissionResult.kNone:
    {
      // no update
      break;
    }
  }
}

public static void example()
{
  string service_provider = "Facebook";
  string player_id = "testuser";
  double score = 10000;

  // kHighScore 를 입력하여 최고 점수인 경우에만 갱신합니다.
  Leaderboard.ScoreSubmissionRequest request =
      new Leaderboard.ScoreSubmissionRequest(
          kPlayerGameScore,
          service_provider,
          player_id,
          score,
      Leaderboard.RankingType.kOrdinal,
      Leaderboard.Timespan.kWeekly,
      Leaderboard.ScoreSubmissionType.kHighScore);

  Leaderboard.SubmitScore (request, onScoreSubmitted);
}

25.4. 示例: 删除排行榜

当因惩罚玩家或玩家注销而需要删除排行榜时,可调用 DeleteScore()DeleteScoreSync() 来删除排行榜。 调用该函数后, AllTimeDailyYesterdayWeeklyLastWeek 所有排行榜数据均会被删除。

下面的示例是拥有2个leaderboard ID时在各个leaderboard ID中删除用户排行榜信息的示例。

Tip

下面的示例是对在服务器代码中删除排行榜的方式的说明,想要直接从Redis/MySQL中手动删除排行榜时,请参考 (高级)直接删除或修复排行榜数据

25.4.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const char *kPlayerGameScore = "player_game";
const char *kGuildGameScore = "guild_game";

void example() {
  string service_provider = "Facebook";
  string player_id = "testuser";

  ScoreDeletionRequestVector requests;

  requests.push_back(
      ScoreDeletionRequest(
          kPlayerGameScore,
          service_provider,
          player_id));

  requests.push_back(
      ScoreDeletionRequest(
          kGuildGameScore,
          service_provider,
          player_id));

  ScoreDeletionResponseVector responses;
  if (not DeleteScoreSync(requests, &responses)) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  BOOST_FOREACH(const ScoreDeletionResponse &response, responses) {
    LOG(INFO) << "result: " << response.result;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
string kPlayerGameScore = "player_game";
string kGuildGameScore = "guild_game";

public static void example()
{
  string service_provider = "Facebook";
  string player_id = "testuser";

  List<Leaderboard.ScoreDeletionRequest> requests =
      new List<Leaderboard.ScoreDeletionRequest> ();

  requests.Add(
      new Leaderboard.ScoreDeletionRequest (
          kPlayerGameScore,
          service_provider,
          player_id));

  requests.Add(
      new Leaderboard.ScoreDeletionRequest (
          kGuildGameScore,
          service_provider,
          player_id));

  List<Leaderboard.ScoreDeletionResponse> responses;
  if (!Leaderboard.DeleteScoreSync (requests, out responses))
  {
    Log.Error ("leaderboard system error");
    return;
  }

  foreach (Leaderboard.ScoreDeletionResponse response in responses)
  {
    Log.Info ("result: {0}", response.Result);
  }
}

25.4.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const char *kPlayerGameScore = "player_game";
const char *kGuildGameScore = "guild_game";


void OnScoreDeleted(
    const ScoreDeletionRequestVector &requests,
    const ScoreDeletionResponseVector &responses,
    const bool &error) {
  if (error) {
    LOG(ERROR) << "leaderboard system error";
    return;
  }

  BOOST_FOREACH(const ScoreDeletionResponse &response, responses) {
    LOG(INFO) << "result: " << response.result;
  }
}


void example() {
  string service_provider = "Facebook";
  string player_id = "testuser";

  ScoreDeletionRequestVector requests;

  requests.push_back(
      ScoreDeletionRequest(
          kPlayerGameScore,
          service_provider,
          player_id));

  requests.push_back(
      ScoreDeletionRequest(
          kGuildGameScore,
          service_provider,
          player_id));

  ScoreDeletionResponseHandler handler = OnScoreDeleted;
  DeleteScore(requests, handler);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
string kPlayerGameScore = "player_game";
string kGuildGameScore = "guild_game";

public static void OnScoreDeleted(
    List<Leaderboard.ScoreDeletionRequest> requests,
    List<Leaderboard.ScoreDeletionResponse> responses,
    bool error)
{
  if (error)
  {
    Log.Error ("leaderboard system error");
    return;
  }

  foreach (Leaderboard.ScoreDeletionResponse response in responses)
  {
    Log.Info ("result: {0}", response.Result);
  }
}

public static void example()
{
  string service_provider = "Facebook";
  string player_id = "testuser";

  List<Leaderboard.ScoreDeletionRequest> requests =
      new List<Leaderboard.ScoreDeletionRequest> ();

  requests.Add (
      new Leaderboard.ScoreDeletionRequest (
          kPlayerGameScore,
          service_provider,
          player_id));

  requests.Add (
      new Leaderboard.ScoreDeletionRequest (
          kGuildGameScore,
          service_provider,
          player_id));

  Leaderboard.DeleteScore (requests, OnScoreDeleted);
}

25.5. 示例: 获取排行榜重置时间表

游戏服务器在与iFun Leaderboard连接后,将自动调取 reset_schedules 信息。 因此只存在返回缓存信息的同步版本函数,不存在非同步版本的函数。

通过 GetLeaderboardResetSchedule() 函数可以获取已注册到 注册重置时间表 中的排行榜重置时间表信息。

该函数分为获取所有重置时间表信息的版本和调取特定重置时间表信息的版本。 无论何种情况,当iFun Leaderboard的MANIFEST.json中不存在reset_schedules,或该信息错误时,均会返回false。

返回所有时间表的版本:

bool GetLeaderboardResetSchedule(
    LeaderboardResetScheduleVector *reset_schedules,
    const string &tag = "");

调取特定重置时间表信息的版本:

// leaderboard_id 와 period 에 맞는 LeaderboardResetSchedule 을 얻어옵니다.
bool GetLeaderboardResetSchedule(const string &leaderboard_id,
                                 const LeaderboardResetSchedule::Period &period,
                                 LeaderboardResetSchedule *reset_schedule,
                                 const string &tag = "");

使用示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
void Example() {
  LeaderboardResetScheduleVector reset_schedules;

  if (not GetLeaderboardResetSchedule(&reset_schedules)) {
    // Failed...
    return;
  }

  BOOST_FOREACH(const LeaderboardResetSchedule &reset_schedule, reset_schedules) {
    LOG(INFO) << "leaderboard id: " << reset_schedule.leaderboard_id
              << ", period: " << reset_schedule.period
              << ", interval: " << reset_schedule.interval
              << ", starts: " << reset_schedule.starts
              << ", end: " << reset_schedule.ends
              << ", latest reset date time: " << reset_schedule.latest_reset_date_time
              << ", upcoming date time" << reset_schedule.upcoming_date_time
              << ", upcoming time: " << reset_schedule.upcoming_time
              << ", next date time" << reset_schedule.next_date_time
              << ", next time: " << reset_schedule.next_time
              << ", expired: " << reset_schedule.expired;
  }
}

通过 Leaderboard.GetResetSchedule() 函数可以获取已注册到 注册重置时间表 中的排行榜重置时间表信息。

该函数分为获取所有重置时间表信息的版本和调取特定重置时间表信息的版本。 无论何种情况,当iFun Leaderboard的MANIFEST.json中不存在reset_schedules,或该信息错误时,均会返回false。

返回所有时间表的版本:

bool GetResetSchedule(out List<Leaderboard.ResetSchedule> reset_schedules,
                      string tag = "");

调取特定重置时间表信息的版本:

// leaderboard_id 와 period 에 맞는 Leaderboard.ResetSchedule 을 얻어옵니다.
bool GetResetSchedule(string leaderboard_id,
                      Leaderboard.ResetSchedulePeriod period,
                      out Leaderboard.ResetSchedule reset_schedule,
                      string tag = "");

使用示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Example()
{
  List<Leaderboard.ResetSchedule> reset_schedules;

  if (!Leaderboard.GetResetSchedule(out reset_schedules)) {
    // Failed...
    return;
  }

  foreach (Leaderboard.ResetSchedule reset_schedule in reset_schedules)
  {
    Log.Info("leaderboard_id: {0}, period: {1}, interval: {2}" +
             ", starts: {3}, end: {4}, latest reset date time: {5}" +
             ", upcoming date time: {6}, upcoming time: {7}" +
             ", next date time: {8}, next time: {9}, expired: {10}",
             reset_schedule.LeaderboardId,
             reset_schedule.ResetSchedulePeriod,
             reset_schedule.Interval,
             reset_schedule.Starts,
             reset_schedule.Ends,
             reset_schedule.LatestResetDateTime,
             reset_schedule.UpcomingDateTime,
             reset_schedule.UpcomingTime,
             reset_schedule.NextDateTime,
             reset_schedule.NextTime,
             reset_schedule.Expired);
  }
}

25.6. 示例: 查看排行榜是否已经重置

下面我们来看下对Leaderboard是否已经重置进行查看的示例。

25.6.1. 同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Example() {
    const string leaderboard_id = "player_score";
    LeaderboardResetSchedule reset_schedule;
    bool success = GetLeaderboardResetSchedule(leaderboard_id,
        LeaderboardResetSchedule::kWeek, &reset_schedule);
    if (not success) {
      return;
    }

    LeaderboardResetScheduleStatusQueryRequest request(
        leaderboard_id,
        LeaderboardResetSchedule::kWeek,
        reset_schedule.latest_reset_date_time);

    LeaderboardResetScheduleStatusQueryResponse response;
    success = GetLeaderboardResetScheduleStatusQuerySync(request, &response);
    if (not success) {
      return;
    }

    LOG(INFO) << "result: " << response.result
              << ", is_reset: " << response.is_reset
              << ", reset_date_time: " << response.reset_date_time;
  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void Example()
{
  string leaderboard_id = "player_score";
  Leaderboard.ResetSchedule reset_schedule;
  if (!Leaderboard.GetResetSchedule (leaderboard_id,
                                     Leaderboard.ResetSchedulePeriod.kWeek,
                                     out reset_schedule))
  {
    return;
  }

  Leaderboard.ResetScheduleStatusQueryRequest request =
      new Leaderboard.ResetScheduleStatusQueryRequest (
          leaderboard_id,
          Leaderboard.ResetSchedulePeriod.kWeek,
          reset_schedule.LatestResetDateTime);

  Leaderboard.ResetScheduleStatusQueryResponse response;
  if (!Leaderboard.GetResetScheduleStatusQuerySync (request, out response))
  {
    return;
  }

  Log.Info("is_reset: {0}, reset_date_time: {1}",
           response.IsReset,
           response.ResetDateTime);
}

25.6.2. 非同步方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void OnResponse(const LeaderboardResetScheduleStatusQueryRequest &request,
                const LeaderboardResetScheduleStatusQueryResponse &response,
                const bool &error) {
  if (error) {
    return;
  }

  LOG(INFO) << "result: " << response.result
            << ", is_reset: " << response.is_reset
            << ", reset_date_time: " << response.reset_date_time;
}


void Example() {
    const string leaderboard_id = "player_score";
    LeaderboardResetSchedule reset_schedule;
    bool success = GetLeaderboardResetSchedule(leaderboard_id,
        LeaderboardResetSchedule::kWeek, &reset_schedule);
    if (not success) {
      return;
    }

    LeaderboardResetScheduleStatusQueryRequest request(
        leaderboard_id,
        LeaderboardResetSchedule::kWeek,
        reset_schedule.latest_reset_date_time);

    LeaderboardResetScheduleStatusQueryResponseHandler handler = OnResponse;
    GetLeaderboardResetScheduleStatusQuery(request, handler);
  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static void OnResetScheduleStatusReceived(
    Leaderboard.ResetScheduleStatusQueryRequest request,
    Leaderboard.ResetScheduleStatusQueryResponse response,
    bool error)
{
  if (error) {
    return;
  }
  Log.Info("is_reset: {0}, reset_date_time: {1}",
           response.IsReset,
           response.ResetDateTime);
}


public static void Example()
{
  string leaderboard_id = "player_score";
  Leaderboard.ResetSchedule reset_schedule;
  if (!Leaderboard.GetResetSchedule (leaderboard_id,
                                     Leaderboard.ResetSchedulePeriod.kWeek,
                                     out reset_schedule))
  {
    return;
  }

  Leaderboard.ResetScheduleStatusQueryRequest request =
      new Leaderboard.ResetScheduleStatusQueryRequest (
          leaderboard_id,
          Leaderboard.ResetSchedulePeriod.kWeek,
          reset_schedule.LatestResetDateTime);

  Leaderboard.GetResetScheduleStatusQuery (
      request, OnResetScheduleStatusReceived);
}

25.7. 示例: 运用多个iFun Leaderboard对Leaderboard请求进行分布式处理

可以通过 游戏服务器端Leaderboard设置参数 对已输入的多个Leaderboard服务器设置tag,指定特定Leaderboard代理 ,请求处理排行榜。

下面的示例单独构建了处理公会排行榜的leaderboard代理和处理 用户排行榜的leaderboard代理,从而使用了两个独立的leaderboard代理。

MANIFEST.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  ...
  "dependency": {
    ...

    "LeaderboardClient": {
      "use_leaderboard" : true,
      "leaderboard_agents": {
        "guild" : {
          "address": "192.168.0.50:12820"
        },
        "user": {
          "address": "192.168.0.100:12820"
        }
      }
    }
  }
  ...
}

Note

如果不需要指定tag,输入””(空字符串)即可。 所有函数的tag parameter默认值为””(空字符串)。 因此,即使函数中未输入tag,也可以和leaderboard代理进行通信。 即,””(空字符串)也通过变为tag的方式来运行。

请求公会排行榜:

现在我们向处理公会排行榜的leaderboard代理请求Top100。 为了简单地说明示例,我们使用同步API。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const string kGuildTag("guild");

void GetGuildRanking() {
  LeaderboardQueryRequest request("guild_ranking", kWeekly,
      LeaderboardRange(LeaderboardRange::kFromTop, 0, 99));

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response, kGuildTag)) {
    return;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static string kGuildTag = "guild";

void GetGuildRanking()
{
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
      "guild_ranking",
      Leaderboard.Timespan.kWeekly,
      new Leaderboard.Range(Leaderboard.RangeType.kFromTop, 0, 99));

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync(request, out response, kGuildTag))
  {
    return;
  }
}

请求用户排行榜:

现在我们向处理用户排行榜的leaderboard代理请求Top100。 为了简单地说明示例,我们使用同步API。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const string kUserTag("user");

void GetUserRanking() {
  LeaderboardQueryRequest request("user_ranking", kWeekly,
      LeaderboardRange(LeaderboardRange::kFromTop, 0, 99));

  LeaderboardQueryResponse response;
  if (not GetLeaderboardSync(request, &response, kUserTag)) {
    return;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static string kUserTag = "user";

void GetUserRanking()
{
  Leaderboard.QueryRequest request = new Leaderboard.QueryRequest(
      "user_ranking",
      Leaderboard.Timespan.kWeekly,
      new Leaderboard.Range(Leaderboard.RangeType.kFromTop, 0, 99));

  Leaderboard.QueryResponse response;
  if (!Leaderboard.GetLeaderboardSync(request, out response, kUserTag))
  {
    return;
  }
}

25.8. 游戏服务器端Leaderboard设置参数

Note

该设置参数是使用iFun Leaderboard的iFun引擎游戏服务器的值。iFun Leaderboard自身的设置参数请参考 iFun Leaderboard设置方法(MANIFEST.json)

可参考 MANIFEST.JSON File 和以下说明,设置Leaderboard客户端的 Component。

  • use_leaderboard: 是否激活与iFun Leaderboard agent的通信。当指定为false时,将以对所有与排行榜有关的请求响应dummy值的测试模式运行。(type=bool, default=false)

  • leaderboard_agents: 通过如下所示的format输入想要访问的Leaderboard代理的连接信息。

    "leaderboard_agents": {
      // iFun Leaderboard agent를 tag 로 구분해서 각각의 접속 정보를 입력합니다.
      "<tag>": {
        // iFun Leaderboard 의 MANIFEST.json 에 기술된 server_tcp_port 를 입력합니다.
        "address": "127.0.0.1:12820"
      },
      ...
    }
    

    Note

    使用tag可向特定iFun Leaderboard agent请求处理排行榜。具体内容请参考 示例: 运用多个iFun Leaderboard对Leaderboard请求进行分布式处理

    当未额外输入tag时,可输入”” (空字符串)。包含””在内,tag不能有重复。