跳到主要内容
版本:v3

排行榜指南

信息

阅读此文档前请先阅读:

  • 排行榜功能介绍,了解排行榜的核心概念及功能。
  • 内建账户指南,排行榜成员类型有 user、object、entity 三种,这里的 user 指内建账户系统中的用户。另外,本文中的 currentUser 指内建账户系统的当前登录用户。

环境要求

  • Unity 2019.4 或更高版本
  • iOS 11 或更高版本,Xcode 版本 14.1 或更高版本
  • Android 5.0(API level 21)或更高版本

权限说明

集成前准备

  1. 参考 准备工作 创建应用、开启内建账户、排行榜服务、绑定 API 域名;

SDK 获取

排行榜功能是数据存储 SDK 的一部分,排行榜 SDK 配置与数据存储 SDK 配置一致;

SDK 可以通过 Unity Package Manager 导入或手动导入,二者任选其一。请根据项目需要选择。

方法一:使用 Unity Package Manager

在项目的 Packages/manifest.json 文件中添加以下依赖:

"dependencies":{
"com.leancloud.realtime": "https://github.com/leancloud/csharp-sdk-upm.git#realtime-2.3.0",
"com.leancloud.storage": "https://github.com/leancloud/csharp-sdk-upm.git#storage-2.3.0",
}

在 Unity 顶部菜单中选择 Window > Package Manager 可查看已经安装在项目中的包。

方法二:手动导入

  1. 下载页 找到 LeanCloud C# SDK 下载地址,下载 LeanCloud-SDK-Realtime-Unity.zip

  2. 解压后的 LeanCloud-SDK-Realtime-Unity.zip 为 Plugins 文件夹,拖拽至 Unity 即可。

SDK 初始化

内建账户 SDK 初始化完成后会同步初始化排行榜功能,因此无需重复初始化;

快速入门

创建排行榜

创建排行榜有 3 种方式:

比如,可以在控制台创建一个名称为 world,成员类型为「内建账户」,排序为 descending,更新策略为 better,重置周期为「每月」的世界排行榜。

create leaderboard

提交成绩

假设玩家已登录(currentUser),通过如下代码即可更新成绩:

var statistic = new Dictionary<string, double>();
statistic["world"] = 20.0;
await LCLeaderboard.UpdateStatistics(currentUser, statistic);

获取名次

接下来我们获取排行榜中的前十,由于之前我们只提交了一个玩家(当前玩家)的成绩,所以结果中只包含一个成绩。

var leaderboard = LCLeaderboard.CreateWithoutData("world");
var rankings = await leaderboard.GetResults(limit: 10);

看过上面这个最简单的接入排行榜的例子后,下面就详细介绍排行榜的各个接口。

成绩管理

更新用户成绩

当用户完成了一局游戏后,你可以在客户端使用 SDK 的 updateStatistic 方法更新该用户的成绩。 不过,从反作弊的角度出发,我们建议在控制台勾选「只允许使用 Master Key 更新分数」,然后在服务端更新成绩。

var statistic = new Dictionary<string, double> {
{ "score", 3458.0 },
{ "kills", 28.0 }
};
await LCLeaderboard.UpdateStatistics(currentUser, statistic);

更新用户成绩需要玩家登录,玩家只能更新自己的成绩。 你可以一次性更新多个排行榜的成绩,比如上面的示例中同时更新了得分(score)和击杀(kills)两个排行榜的成绩。

客户端无法更新 object 和 entity 的成绩。 如需更新其他用户、object、entity 的成绩,需要使用 REST APISDK 提供的管理接口

删除用户成绩

玩家也可以删除自己的成绩:

await LCLeaderboard.DeleteStatistics(currentUser, new List<string> { "world" });

和更新成绩一样,玩家只能删除自己的成绩。 如需删除其他用户、object、entity 的成绩,需要使用 REST APISDK 提供的管理接口

查询排行榜成员成绩

已登录用户可以通过 GetStatistics 方法查询其他用户在所有排行榜中的成绩:

var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
var statistics = await LCLeaderboard.GetStatistics(otherUser);
foreach(var statistic in statistics) {
Debug.Log(statistic.Name);
Debug.Log(statistic.Value);
}

更多的场景下,只关心用户在某个或某几个排行榜中的成绩。 查询时指定相应排行榜的名称即可:

var statistics = await LCLeaderboard.GetStatistics(otherUser, new List<string> { "world" });

类似地,可以查询 object 和 entity 的成绩。

例如,假定武器排行榜是 object 排行榜:

var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
var statistics = await LCLeaderboard.GetStatistics(excalibur, new List<string> { "weapons" });

如果武器排行榜是 entity 排行榜:

var statistics = await LCLeaderboard.GetStatistics("excalibur", new List<string> { "weapons" });

最后,还可以查询一组成员的成绩:

var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
var anotherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "672a127144a90d00536f3456");
var statistics = await LCLeaderboard.GetStatistics({otherUser, anotherUser}, new List<string> { "world" });

var oneObject = LCObject.CreateWithoutData<LCObject>("abccb27133a90ddd536ffffa");
var anotherUser = LCObject.CreateWithoutData<LCObject>("672a1279345777005a2b2444");
var statistics = await LCLeaderboard.GetStatistics({oneObject, anotherObject}, new List<string> { "weapons" });

var statistics = await LCLeaderboard.GetStatistics({"Sylgr", "Leiptr"}, new List<string> { "rivers" });

获取排行榜结果

通过 Leaderboard#getResults 方法可以获取排行榜结果。 最常见的使用场景是获取排名前 N 的用户成绩和获取当前登录用户附近的排名。

首先,我们构造一个排行榜实例:

var leaderboard = LCLeaderboard.CreateWithoutData("world");

LCLeaderboard.CreateWithoutData 方法接受两个参数:

public static LCLeaderboard CreateWithoutData(string statisticName, string memberType = LCLeaderboard.USER_MEMBER_TYPE)
  • statisticName 为排行榜名称,这里需要传入云端已经存在的排行榜名称。上例中是 world
  • memberType 为排行榜成员类型,传入 LCLeaderboard.USER_MEMBER_TYPE 表示成员类型为用户,传入 LCLeaderboard.ENTITY_MEMBER_TYPE 表示成员类型为 entity,成员类型为 object 时请传入相应 Class 名称。上例中省略了这一参数,表示使用默认值,成员类型为用户。

构造排行榜实例后,调用该实例上的相应方法即可获取排名。

获取指定区间的排名

获取排行榜的 Top 10:

var rankings = await leaderboard.GetResults(limit: 10);

GetResults 方法可以指定以下参数限制查询范围:

参数名类型说明
aroundUserLCUser获取某用户附近的排名,详见下节。
aroundObjectLCObject获取某 object 附近的排名,详见下节
aroundEntitystring获取某 entity 附近的排名,详见下节。
limitnumber限制返回的结果数量,默认 10。
skipnumber指定从某个位置开始获取,与 limit 一起可以实现翻页,默认 0。
selectKeysstring[]指定返回的 Ranking 中的 user 需要包含的属性,详见下文。
includeKeysstring[]指定返回的 Ranking 中的 user 需要包含的 Pointer 属性,详见下文。
includeStatisticsstring[]指定返回的 Ranking 中需要包含的其他成绩,详见下文。
versionnumber指定返回某个历史版本的成绩。

返回的结果是一个排名数组(Ranking[]),Ranking 上有如下属性:

属性类型说明
Rankint排名,从 0 开始
UserLCUser该成绩的用户(user 排行榜)
ObjectLCObject该成绩的 object(object 排行榜)
Entitystring该成绩的 entity(entity 排行榜)
Valuedouble成绩
IncludedStatisticsList<Statistic>该成员在其他排行榜的成绩

默认情况下返回的排行榜结果中的 user 是一个指向 LCUser 的 Pointer。 如果想要像下面这个例子一样,在排行榜结果中显示用户名或者其他的用户属性(对应 _User 表中的属性),那么需要使用 selectKeys 指定需要包含的属性。

排名UsernameScore↓
0Genji3458
1Lúcio3252
2D.Va3140
var rankings = await leaderboard.GetResults(limit: 10,
selectKeys: new List<string> { "nickname" });

如果想要在排行榜结果中包含用户的其他成绩,可以使用 includeStatistics。 例如,查询得分排行榜时同时返回相应用户的击杀数:

排名UsernameScore↓Kills
0Genji345828
1Lúcio32522
2D.Va314031
var rankings = await leaderboard.GetResults(limit: 10, selectKeys: new List<string> { "username" }
includeStatistics: new List<string> { "kills" });

如果想要包含的属性是 Pointer 类型或文件类型,那么 selectKeys 只会返回 Pointer 本身。 想要一并获取 Pointer 指向的另一个 class 的数据的话,需要额外使用 includeKeys 指定。 例如,假设 club 是一个指向 Club 类的 Pointer:

var leaderboard = LCLeaderboard.CreateWithoutData("weapons", "Weapon");
var rankings = await leaderboard.GetResults(limit: 10,
selectKeys: new List<string> { "name", "club" },
includeKeys: new List<string> { "club" });

注意,排行榜 不保证成绩并列的成员之间的先后顺序。 例如,假设 A、B、C 的成绩为 42、32、32,且排行榜的排序策略为降序,那么查询排行榜的返回结果可能是 A、B、C,也可能是 A、C、B。

当成绩相同时,如果需要其他因素去设置排名可以参考如下示例(示例是通过成绩上传的时间戳去判断排名,当成绩相同时,越早/晚提交,排名越靠前/后)

Android 请求示例:
public class RankingActivity extends AppCompatActivity{

// ...

/**
* 上传/更新成绩
*
* */
private void submitScore() {

double score = 324.45; // 实际的分数
long ts = System.currentTimeMillis() / 1000; // 时间戳
double last_score = toEncode( score, ts); // 将实际分数与时间戳组合生成一个新的数据上传到服务器

Map<String, Double> statistic = new HashMap<>();
statistic.put("word", last_score);

LCLeaderboard.updateStatistic(LCUser.currentUser(), statistic).subscribe(new Observer<LCStatisticResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}

@Override
public void onNext(@NotNull LCStatisticResult jsonObject) {
Log.e(TAG, "onNext: "+jsonObject.getResults().get(0).toString());

}

@Override
public void onError(@NotNull Throwable throwable) {
ToastUtil.showCus(throwable.getMessage(), ToastUtil.Type.ERROR);
}

@Override
public void onComplete() {}
});

}

/**
* 查询排行榜列表
* */
private void searchRankList() {
// 获取排行榜的实例
LCLeaderboard leaderboard = LCLeaderboard.createWithoutData("word");

leaderboard.getResults(0, 10, null, null).subscribe(new Observer<LCLeaderboardResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}

@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onNext(@NotNull LCLeaderboardResult leaderboardResult) {
List<LCRanking> rankings = leaderboardResult.getResults();
for(int i=0; i<rankings.size(); i++){
/**
* 将查询的方法进行解密
*/
double score = rankings.get(i).getStatisticValue(); // 获取查询到的分数
String formatScore = String.format("%.3f", score); // 将 double 类型的分数系列化为保留小数点后3位的字符串
BigDecimal decimalValue = new BigDecimal(formatScore);
long longPart = decimalValue.longValue(); // 获取查询到的 StatisticValue 的整数部分
float floatPart = decimalValue.subtract(BigDecimal.valueOf(longPart)).floatValue(); // 获取查询到的 StatisticValue 的小数部分

int[] decryptedScoreTs = toDecode(longPart); // 将整数部分进行解密操作
int decryptedScore = decryptedScoreTs[0]; // 获取实际分数的整数部分
long decryptedTs = decryptedScoreTs[1]; // 获取提交成绩时的时间戳

BigDecimal bigDecimalValue = new BigDecimal(Integer.toString(decryptedScore))
.add(new BigDecimal(Float.toString(floatPart))); // 将实际分数的整数部分拼接上小数部分得到实际的分数
double doubleValue = bigDecimalValue.doubleValue(); // 将实际分数转化为 double 类型

Log.e(TAG, "解析后的score:"+doubleValue + "解析后的时间戳:"+ decryptedTs );

}

}

@Override
public void onError(@NotNull Throwable throwable) {
}

@Override
public void onComplete() {}
});

}

/**
* score 实际的分数
* ts 时间戳
* 将实际分数与时间戳组合生成一个新的数据上传到服务器
*/
public static double toEncode(double score, long ts) {
int int_score = (int) score; // 实际分数的整数部分
float float_score = (float) (score - int_score); // 实际分数的小数部分

/**
* 当排行榜使用降序排列,分数相同时,时间越近,排名靠前,使用这行代码
*/
// long encryptedScoreTs = ((long) int_score << 32) | (ts & 0xFFFFFFFFL); // 将整数部分分数与时间戳进行加密处理合并成一个新的 score

/**
* 当排行榜使用降序排列,分数相同时,时间越近,排名靠后,使用这行代码
*/
long encryptedScoreTs = ((long) int_score << 32) - (ts & 0xFFFFFFFFL); // 将整数部分分数与时间戳进行加密处理合并成一个新的 score

double newScore = (double)encryptedScoreTs + float_score; // 然后将加密生成的数据拼接上小数部分的数据,上传到服务器
return newScore;
}

/**
* 将加密的数据进行解析出实际分数和当时提交成绩时的时间戳
*
*/
public static int[] toDecode(long encryptedNewScore) {
/**
* 当排行榜使用降序排列,分数相同时,时间越近,排名靠前,使用这行代码
*/

// int score = (int) (encryptedNewScore >> 32);

/**
* 当排行榜使用降序排列,分数相同时,时间越近,排名靠后,使用这行代码
*/
int score = (int) (encryptedNewScore >> 32) + 1;
long ts = encryptedNewScore & 0xFFFFFFFFL;
return new int[]{score, (int) ts};
}


}

获取当前用户附近的排名

排名UsernameScore↓
24Bastion716
25 (You)Widowmaker698
26Hanzo23

如果想达到类似上表的效果,在调用 GetResults 方法时额外传入当前用户即可:

var rankings = await leaderboard.GetResults(aroundUser: currentUser, limit: 3, selectKeys: new List<string> { "username" });

上面的代码示例中,limit 的值为 3,表示获取与当前玩家相邻的前后两个玩家的排名,当前玩家会在结果的中间位置。 如仅需获取当前玩家排名,可指定 limit 为 1。

类似地,可以获取某个 object 或 entity 附近的排名。 例如,获取武器榜上和某件武器排名相近的武器,同时获取这些武器的名称、攻击力、等级:

var leaderboard = LCLeaderboard.CreateWithoutData("weapons", "Weapon");
var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
var rankings = await leaderboard.GetResults(aroundObject: excalibur, limit: 3, selectKeys: new List<string> { "name", "attack", "level" });

上面的例子中假定武器排行榜是通过 object 排行榜实现的,存储武器信息的 Class 为 Weapon。 如果武器排行榜是通过 entity 排行榜实现的,且只需获取武器的名称,那么相应的代码为:

var leaderboard = LCLeaderboard.CreateWithoutData("weapons", LCLeaderboard.ENTITY_MEMBER_TYPE);
var rankings = await leaderboard.GetResults(aroundEntity: "excalibur", limit: 3);

TapTap 好友排行榜列表

获取 TapTap 互关好友在游戏中的排行榜成绩列表(包括自己)。

 ReadOnlyCollection<TDSLeaderBoardRanking> leaderBoards = await TDSLeaderBoardRanking.QueryTapFriendsLeaderBoard("world",0,10);
string printData = "";
foreach(TDSLeaderBoardRanking leaderBoard in leaderBoards){
printData = printData + $"name = {leaderBoard.StatisticName} value = {leaderBoard.StatisticValue} rank = {leaderBoard.Rank} user = [ id = {leaderBoard.User.ObjectId} name = {leaderBoard.User["nickname"]} \n";
}
Console.WriteLine(printData);

参数 name 为排行榜的名称, fromlimit 为分页获取数据时指定的起始位置和数据长度,返回为查询的结果数据,数据结构如下:

字段名称字段内容字段类型
statisticName排行榜名称String
statisticValue排行榜中的成绩int
rank排行榜中的名次, 0 表示第一名,以此类推int
user排行榜数据对应的用户TDSUser

控制台

在排行榜控制台(游戏服务 > 云服务 > 排行榜),你可以:

  • 新建、重置、编辑、删除排行榜。
  • 查看排行榜当前版本的数据、删除成绩、下载排行榜的历史数据归档文件。
  • 设置是否允许客户端查询前一版本,是否只允许使用 Master Key 更新分数。

SDK 管理接口

除了通过控制台管理排行榜外,C# SDK 和 Java SDK 也提供了管理接口,可以在服务端等受信任的环境下使用。 另外,也可以直接调用 REST API 提供的管理接口。

下面我们先介绍 SDK 提供的管理接口。

警告

请注意,调用管理接口 API 需要在 SDK 初始化时使用 masterKey,因此只能在服务端等可信任的环境中调用,不得在客户端使用。

LCApplication.Initialize({{appid}}, {{appkey}}, "https://xxx.example.com", {{masterkey}});
LCApplication.UseMasterKey = true;

创建排行榜

var leaderboard = await LCLeaderboard.CreateLeaderboard("time", order: LCLeaderboardOrder.ASCENDING);

可以指定的参数类型和默认值如下:

public static async Task<LCLeaderboard> CreateLeaderboard(string statisticName,
LCLeaderboardOrder order = LCLeaderboardOrder.Descending,
LCLeaderboardUpdateStrategy updateStrategy = LCLeaderboardUpdateStrategy.Better,
LCLeaderboardVersionChangeInterval versionChangeInterval = LCLeaderboardVersionChangeInterval.Week,
string memberType = LCLeaderboard.USER_MEMBER_TYPE)
  • statisticName 所排名的成绩名字。
  • order 排序,可以传入 LCLeaderboardOrder.DescendingLCLeaderboardOrder.Ascending
  • updateStrategy 成绩更新策略,可以传入 LCLeaderboardUpdateStrategy.BetterLCLeaderboardUpdateStrategy.LastLCLeaderboardUpdateStrategy.Sum
  • versionChangeInterval 自动重置周期,可以传入 LCLeaderboardVersionChangeInterval.NeverLCLeaderboardVersionChangeInterval.DayLCLeaderboardVersionChangeInterval.WeekLCLeaderboardVersionChangeInterval.Month
  • memberType 成员类型,传入 LCLeaderboard.USER_MEMBER_TYPE 表示成员类型为用户,传入 LCLeaderboard.ENTITY_MEMBER_TYPE 表示成员类型为 entity,成员类型为 object 时请传入相应 Class 名称。

手动重置排行榜

var leaderboard = LCLeaderboard.CreateWithoutData("score");
await leaderboard.Reset();

获取排行榜属性

通过以下接口可以获取当前排行榜的属性,例如:重置周期、版本号、更新策略等。

var leaderboardData = await LCLeaderboard.GetLeaderboard("world");

修改排行榜属性

排行榜创建后,仅可修改自动重置周期和成绩更新策略,其他属性无法修改。

var leaderboard = LCLeaderboard.CreateWithoutData("equip");
await leaderboard.UpdateVersionChangeInterval(LCLeaderboardVersionChangeInterval.Week);
await leaderboard.UpdateUpdateStrategy(LCLeaderboardUpdateStrategy.Last);

删除排行榜

var leaderboard = lcleaderboard.createwithoutdata("equip");
await leaderboard.destroy();

删除排行榜会删除该排行榜的所有数据,包括当前数据及所有历史版本归档。

更新排行榜成员成绩

有些情况下,你会想要绕过排行榜的更新策略强制更新用户的成绩,你可以使用 overwrite 参数实现这一需求:

var statistic = new Dictionary<string, double> {
{ "score", 0.0 }
};
await LCLeaderboard.UpdateStatistics(user, statistic, overwrite: true);

object 和 entity 排行榜只支持在服务端使用 Master Key 更新,但仍会遵循排行榜的更新策略:

var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
await LCLeaderboard.UpdateStatistics(excalibur, statistic);

如果需要强制更新,同样需要指定 overwrite 为真:

await LCLeaderboard.UpdateStatistics("Vimur", statistic, overwrite: true);

删除排行榜成员成绩

在服务端使用 Master Key 可以删除任意用户、object、entity 的成绩:

var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
await LCLeaderboard.DeleteStatistics(otherUser, new List<string> { "world" });

var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
await LCLeaderboard.DeleteStatistics(excalibur, new List<string> { "weapons" });

await LCLeaderboard.DeleteStatistics("Vimur", new List<string> { "rivers" });

REST API

下面我们介绍排行榜相关的 REST API 接口。 开发者可以自行编写程序或脚本调用这些接口在服务端进行管理性质的操作。

请求格式

对于 POST 和 PUT 请求,请求的主体必须是 JSON 格式,而且 HTTP Header 的 Content-Type 需要设置为 application/json

请求的鉴权是通过 HTTP Header 里面包含的键值对来进行的,参数如下表:

KeyValue含义来源
X-LC-Id{{appid}}当前应用的 App Id(即 Client Id可在控制台查看
X-LC-Key{{appkey}}当前应用的 App Key(即 Client Token可在控制台查看

管理接口需要使用 Master KeyX-LC-Key: {{masterkey}},masterMaster KeyServer Secret,同样可在控制台查看。

详见文档关于应用凭证的说明。

Base URL

REST API 请求的 Base URL(下文 curl 示例中用 {{host}} 表示)即应用的 API 自定义域名,可以在控制台绑定、查看。详见文档关于域名的说明。

管理排行榜

创建排行榜

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"statisticName": "world", "memberType": "_User", "order": "descending", "updateStrategy": "better", "versionChangeInterval": "month"}' \
https://{{host}}/1.1/leaderboard/leaderboards
参数约束说明
statisticName必须排行榜的名称,创建后不可修改。
memberType必须排行榜的成员类型,创建后不可修改。可填写 _Entity_User 及其他已有的 class 名称。
order可选排行榜的排序策略,创建后不可修改。可选项有 ascendingdescending,默认为 descending
updateStrategy可选可选项有 betterlastsum,默认为 better
versionChangeInterval可选可选项有 dayweekmonthnever,默认为 week

返回的主体是一个 JSON 对象,包含创建排行榜时传入的所有参数,同时包括以下信息:

  • version 为排行榜当前版本号。
  • expiredAt 为下次过期(重置)时间。
  • activatedAt 当前版本的开始时间。
{
"objectId": "5b62c15a9f54540062427acc",
"statisticName": "world",
"memberType": "_User",
"versionChangeInterval": "month",
"order": "descending",
"updateStrategy": "better",
"version": 0,
"createdAt": "2018-08-02T08:31:22.294Z",
"updatedAt": "2018-08-02T08:31:22.294Z",
"expiredAt": {
"__type": "Date",
"iso": "2018-08-31T16:00:00.000Z"
},
"activatedAt": {
"__type": "Date",
"iso": "2018-08-02T08:31:22.290Z"
}
}

获取排行榜属性

通过这个接口来查看当前排行榜的属性,例如更新策略、当前版本号等。

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>

返回的 JSON 对象包含该排行榜的所有信息:

{
"objectId": "5b0b97cf06f4fd0abc0abe35",
"statisticName": "world",
"memberType": "_User",
"order": "descending",
"updateStrategy": "better",
"version": 5,
"versionChangeInterval": "day",
"expiredAt": { "__type": "Date", "iso": "2018-05-02T16:00:00.000Z" },
"activatedAt": { "__type": "Date", "iso": "2018-05-01T16:00:00.000Z" },
"createdAt": "2018-04-28T05:46:58.579Z",
"updatedAt": "2018-05-01T01:00:00.000Z"
}

修改排行榜属性

这个接口可以用来修改排行榜的 updateStrategyversionChangeInterval 属性,其他属性不可修改。可以只更新某一个属性,例如只修改 versionChangeInterval:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"versionChangeInterval": "day"}' \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>

返回的 JSON 对象包含更新的属性信息及 updatedAt 字段。

{
"objectId": "5b0b97cf06f4fd0abc0abe35",
"versionChangeInterval": "day",
"updatedAt": "2018-05-01T08:01:00.000Z"
}

重置排行榜

无论排行榜的重置策略是什么,你都可以通过这个方法重置排行榜。重置时当前版本的数据清空,同时会归档到 csv 文件以供下载,排行榜的 version 会自动加一。

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>/incrementVersion

返回的 JSON 会显示重置后的当前版本号,下一次过期时间 expiredAt,当前版本的开始时间 activatedAt

{
"objectId": "5b0b97cf06f4fd0abc0abe35",
"version": 7,
"expiredAt": { "__type": "Date", "iso": "2018-06-03T16:00:00.000Z" },
"activatedAt": { "__type": "Date", "iso": "2018-05-28T06:02:56.169Z" },
"updatedAt": "2018-05-28T06:02:56.185Z"
}

获取历史数据归档文件

因为每个排行榜最多保存 60 个归档文件,我们建议定期使用这个接口获取归档文件后另行备份保存。

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>/archives

返回的对象会按照 createdAt 降序排列。其中 file_key 是文件的名称,url 是文件的下载地址,status 包含以下状态:

  • scheduled:进入归档任务队列,还未归档,这个状态通常极短。
  • inProgress:正在归档中。
  • failed:归档失败,出现这种情况请提交工单联系技术支持。
  • completed:归档已完成。
{
"results": [
{
"objectId": "5b0b9da506f4fd0abc0abe6e",
"statisticName": "wins",
"version": 9,
"status": "completed",
"url": "https://lc-paas-files.cn-n1.lcfile.com/yK5s6YJztAwEYiWs.csv",
"file_key": "yK5s6YJztAwEYiWs.csv",
"activatedAt": { "__type": "Date", "iso": "2018-05-28T06:11:49.572Z" },
"deactivatedAt": { "__type": "Date", "iso": "2018-05-30T06:11:49.951Z" },
"createdAt": "2018-05-01T16:00.00.000Z",
"updatedAt": "2018-05-28T06:11:50.129Z"
}
]
}

删除排行榜

这个接口将删除排行榜的所有数据,包括当前版本的数据及所有归档文件,删除后无法恢复,请谨慎操作。

删除时只需要指定排行榜的名称 statisticName。

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>

删除成功时返回空 JSON 对象:

{}

管理成绩

更新成绩

使用 Master Key 可以更新任意成绩,但更新成绩时仍然遵循排行榜的 updateStrategy 属性。

更新用户成绩时需指定相应用户的 objectId

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "world", "statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/users/<objectId>/statistics

返回的数据是服务端当前使用的分数:

{
"results": [
{
"statisticName": "wins",
"version": 0,
"statisticValue": 5
},
{
"statisticName": "world",
"version": 2,
"statisticValue": 91
}
]
}

类似地,更新 object 成绩时需指定相应 object 的 objectId

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "weapons","statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/objects/<objectId>/statistics

更新 entity 成绩时则需指定相应的字符串:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "cities","statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/entities/<entityString>/statistics

当前用户可以更新自己的成绩,这个不属于管理接口,不需要 Master Key,但需要传入当前用户的 sessionToken(客户端 SDK 更新当前用户的成绩封装了这一接口):

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: <sessionToken>" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "world", "statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/users/self/statistics

强制更新成绩

附加 overwrite=1 会无视更新策略 better 及 sum,强制使用 last 策略更新用户的成绩。 比如,发现某个用户存在作弊行为时,可以使用这个接口强制更新用户的成绩。

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 10}]' \
https://{{host}}/1.1/leaderboard/users/<uid>/statistics?overwrite=1

返回的数据是当前服务端使用的分数:

{ "results": [{ "statisticName": "wins", "version": 0, "statisticValue": 10 }] }

类似地,附加 overwrite=1 可以强制更新 object 成绩和 entity 成绩。

删除成绩

如果不希望某个用户出现在榜单中,可以使用该接口删除用户的成绩以及在榜单中的排名(仅删除当前排行榜的成绩,不能删除历史版本的成绩)。

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
https://{{host}}/1.1/leaderboard/users/<uid>/statistics?statistics=wins,world

成功删除时返回空对象:

{}

类似地,可以删除 object 的成绩:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
--data-urlencode 'statistics=weapons,equipments' \
https://{{host}}/1.1/leaderboard/objects/<objectId>/statistics

以及 entity 的成绩:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
--data-urlencode 'statistics=cities' \
https://{{host}}/1.1/leaderboard/entities/<entityString>/statistics

同样,当前用户可以删除自己的成绩,这个不属于管理接口,不需要 Master Key,但需要传入当前用户的 sessionToken(客户端 SDK 删除当前用户的成绩封装了这一接口):

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: <sessionToken>" \
-H "Content-Type: application/json" \
https://{{host}}/1.1/leaderboard/users/self/statistics?statistics=wins,world

查询成绩

通过 REST API 可以查询成绩,这些接口不属于管理接口,不需要 Master Key

查询某个成绩

指定用户的 objectId 即可获取该用户的成绩。 你可以在请求 url 中指定多个 statistics 来获得多个排行榜中的成绩,排行榜名称用英文逗号 , 隔开,如果不指定将会返回该用户参与的所有排行榜中的成绩。

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
--data-urlencode 'statistics=wins,world' \
https://{{host}}/1.1/leaderboard/users/<objectId>/statistics

返回结果:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 5,
"version": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "60d950629be318a249000001"
}
},
{
"statisticName": "world",
"statisticValue": 91,
"version": 0,
"user": {...}
}
]
}

类似地,指定 object 的 objectId 可以查询该 object 参与的排行榜的成绩:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
--data-urlencode 'statistics=wins,world' \
https://{{host}}/1.1/leaderboard/objects/<objectId>/statistics

返回示例:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 5,
"version": 0,
"object": {
"__type": "Pointer",
"className": "Weapon",
"objectId": "60d1af149be3180684000002"
}
},
{
"statisticName": "world",
"statisticValue": 91,
"version": 0,
"object": {
"__type": "Pointer",
"className": "Weapon",
"objectId": "60d1af149be3180684000002"
}
}
]
}

获取某个 entity 成绩时则需指定该 entity 的字符串:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
--data-urlencode 'statistics=wins,world' \
https://{{host}}/1.1/leaderboard/entities/<entityString>/statistics

返回示例:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 5,
"version": 0,
"entity": "1a2b3c4d"
},
{
"statisticName": "world",
"statisticValue": 91,
"version": 0,
"entity": "1a2b3c4d"
}
]
}

查询一组成绩

通过这个接口可以一次性拉取多个 user 的成绩,最多不超过 200 个。在请求中,需要在 body 中传入 user 的 objectId 数组。

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '["60d950629be318a249000001", "60d950629be318a249000000"]'
https://{{host}}/1.1/leaderboard/users/statistics/<statisticName>

查询一组成绩的返回结果与查询单个成绩类似:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 1,
"version": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "60d950629be318a249000001"
}
},
{
"statisticName": "wins",
"statisticValue": 2,
"version": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "60d950629be318a249000000"
}
}
]
}

类似地,传入 object 的 objectId 数组可以一次性获取多个 object 的成绩(最多不超过 200 个):

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '["60d950629be318a249000001", "60d950629be318a249000000"]'
https://{{host}}/1.1/leaderboard/objects/statistics/<statisticName>

传入 entity 的字符串数组则可以一次性获取多个 entity 的成绩(最多不超过 200 个):

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '["Vimur", "Fimbulthul"]'
https://{{host}}/1.1/leaderboard/entities/statistics/<statisticName>

查询排行榜

获取区间排名

你可以使用这个接口来获取 Top 排名。

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=20' \
--data-urlencode 'selectKeys=username,club' \
--data-urlencode 'includeKeys=club' \
--data-urlencode 'includeStatistics=wins' \
https://{{host}}/1.1/leaderboard/leaderboards/user/<statisticName>/ranks
参数约束说明
startPosition可选排行头部起始位置,默认为 0。
maxResultsCount可选最大返回数量,默认为 20。
selectKeys可选返回用户在 _User 表的其他字段,支持多个字段,用英文逗号 , 隔开。出于安全性考虑,在非 masterKey 请求下不返回敏感字段 emailmobilePhoneNumber
includeKeys可选返回用户在 _User 表的 pointer 字段的详细信息,支持多个字段,用英文逗号 , 隔开。为确保安全,在非 masterKey 请求下不返回敏感字段 emailmobilePhoneNumber
includeStatistics可选返回该用户在其他排行榜中的成绩,如果传入了不存在的排行榜名称,将会返回错误。
version可选返回指定 version 的排行结果,默认返回当前版本的数据。
count可选值为 1 时返回该排行榜中的成员数量,默认为 0。

返回 JSON 对象:

{
"results": [
{
"statisticName": "world",
"statisticValue": 91,
"rank": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"updatedAt": "2021-07-21T03:08:10.487Z",
"username": "zw1stza3fy701rvgxqwiikex7",
"createdAt": "2020-09-04T04:23:04.795Z",
"club": {
"objectId": "60f78f98d9f1465d3b1da12d",
"name": "board games",
"updatedAt": "2021-07-21T03:08:08.692Z",
"createdAt": "2021-07-21T03:08:08.692Z",
},
"objectId": "5f51c1287628f2468aa696e6"
}
},
{...}
],
"count": 500
}

查询 object 排行榜的 Top 排名的接口与之类似,只是将 user 替换为 object

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'selectKeys=name,image' \
--data-urlencode 'includeKeys=image' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/object/<statisticName>/ranks

返回结果:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 4,
"rank": 0,
"object": {
"__type": "Pointer",
"className": "Weapon",
"name": "sword",
"image": {
"bucket": "test_files",
"provider": "leancloud",
"name": "sword.jpg",
"url": "https://example.com/sword.jpg",
"objectId": "60d2f3a39be3183377000002",
"__type": "File"
},
"objectId": "60d2f22f9be318328b000007"
}
},
{
"statisticName": "wins",
"statisticValue": 3,
"rank": 1,
"object": {...}
}
],
"count": 500
}

同理,URL 中的 user 替换为 entity 可查询 entity 排行榜的 Top 排名:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/entity/<statisticName>/ranks

返回结果:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 4,
"rank": 0,
"entity": "1234567890"
},
{
"statisticName": "wins",
"statisticValue": 3,
"rank": 1,
"entity": "2345678901"
}
],
"count": 500
}

获取附近排名

在 URL 末端附加相应的 objectId 可获取某用户或 object 附近的排名。

获取某用户附近的排名:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=20' \
--data-urlencode 'selectKeys=username,club' \
--data-urlencode 'includeKeys=club' \
https://{{host}}/1.1/leaderboard/leaderboards/user/<statisticName>/ranks/<objectId>

参数含义参见上面获取区间排名一节。 获取附近排名的返回结果与获取区间排名类似。

{
"results": [
{
"statisticName": "wins",
"statisticValue": 3,
"rank": 2,
"user": {...}
},
{
"statisticName": "wins",
"statisticValue": 2.5,
"rank": 3,
"user": {
"__type": "Pointer",
"className": "_User",
"username": "kate",
"club": {
"objectId": "60f78f98d9f1465d3b1da12d",
"name": "board games",
"updatedAt": "2021-07-21T03:08:08.692Z",
"createdAt": "2021-07-21T03:08:08.692Z",
},
"objectId": "60d2faa99be3183623000001"
}
},
{
"statisticName": "wins",
"statisticValue": 2,
"rank": 4,
"user": {...}
}
],
"count": 500
}

获取某 object 附近的排名:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'selectKeys=name,image' \
--data-urlencode 'includeKeys=image' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/object/<statisticName>/ranks/<objectId>

同理,在 URL 末端附加 entity 字符串即可获取该 entity 附近的排名:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/entity/<statisticName>/ranks/<id>

视频教程

可以参考视频教程:如何接入 TapTap 排行榜功能,了解如何在 Untiy 项目中接入排行榜功能。

更多视频教程见开发者学堂。因为 SDK 功能在不断完善,视频教程可能出现与新版 SDK 功能不一致的地方,以当前文档为准。