using System; using System.Threading.Tasks; using System.Collections.Generic; using LeanCloud.Storage.Internal; using System.IO; using System.Text; namespace LeanCloud { /// /// 排行榜顺序 /// public enum AVLeaderboardOrder { /// /// 升序 /// ASCENDING, /// /// 降序 /// DESCENDING } /// /// 排行榜更新策略 /// public enum AVLeaderboardUpdateStrategy { /// /// 更好地 /// BETTER, /// /// 最近的 /// LAST, /// /// 总和 /// SUM, } /// /// 排行榜刷新频率 /// public enum AVLeaderboardVersionChangeInterval { /// /// 从不 /// NEVER, /// /// 每天 /// DAY, /// /// 每周 /// WEEK, /// /// 每月 /// MONTH } /// /// 排行榜类 /// public class AVLeaderboard { /// /// 成绩名字 /// /// The name of the statistic. public string StatisticName { get; private set; } /// /// 排行榜顺序 /// /// The order. public AVLeaderboardOrder Order { get; private set; } /// /// 排行榜更新策略 /// /// The update strategy. public AVLeaderboardUpdateStrategy UpdateStrategy { get; private set; } /// /// 排行榜版本更新频率 /// /// The version change intervak. public AVLeaderboardVersionChangeInterval VersionChangeInterval { get; private set; } /// /// 版本号 /// /// The version. public int Version { get; private set; } /// /// 下次重置时间 /// /// The next reset at. public DateTime NextResetAt { get; private set; } /// /// 创建时间 /// /// The created at. public DateTime CreatedAt { get; private set; } /// /// Leaderboard 构造方法 /// /// 成绩名称 AVLeaderboard(string statisticName) { StatisticName = statisticName; } AVLeaderboard() { } /// /// 创建排行榜对象 /// /// 排行榜对象 /// 名称 /// 排序方式 /// 版本更新频率 /// 成绩更新策略 public static Task CreateLeaderboard(string statisticName, AVLeaderboardOrder order = AVLeaderboardOrder.DESCENDING, AVLeaderboardUpdateStrategy updateStrategy = AVLeaderboardUpdateStrategy.BETTER, AVLeaderboardVersionChangeInterval versionChangeInterval = AVLeaderboardVersionChangeInterval.WEEK) { if (string.IsNullOrEmpty(statisticName)) { throw new ArgumentNullException(nameof(statisticName)); } var data = new Dictionary { { "statisticName", statisticName }, { "order", order.ToString().ToLower() }, { "versionChangeInterval", versionChangeInterval.ToString().ToLower() }, { "updateStrategy", updateStrategy.ToString().ToLower() }, }; var command = new AVCommand("leaderboard/leaderboards", "POST", data: data); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { var leaderboard = Parse(t.Result.Item2); return leaderboard; } catch (Exception e) { throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); } }); } /// /// 创建排行榜对象 /// /// 排行榜对象 /// 名称 public static AVLeaderboard CreateWithoutData(string statisticName) { if (string.IsNullOrEmpty(statisticName)) { throw new ArgumentNullException(nameof(statisticName)); } return new AVLeaderboard(statisticName); } /// /// 获取排行榜对象 /// /// 排行榜对象 /// 名称 public static Task GetLeaderboard(string statisticName) { return CreateWithoutData(statisticName).Fetch(); } /// /// 更新用户成绩 /// /// 更新的成绩 /// 用户 /// 成绩 /// 是否强行覆盖 public static Task> UpdateStatistics(AVUser user, Dictionary statistics, bool overwrite = false) { if (user == null) { throw new ArgumentNullException(nameof(user)); } if (statistics == null || statistics.Count == 0) { throw new ArgumentNullException(nameof(statistics)); } var data = new List(); foreach (var statistic in statistics) { var kv = new Dictionary { { "statisticName", statistic.Key }, { "statisticValue", statistic.Value }, }; data.Add(kv); } var path = string.Format("leaderboard/users/{0}/statistics", user.ObjectId); if (overwrite) { path = string.Format("{0}?overwrite=1", path); } var dataStr = Json.Encode(data); var dataStream = new MemoryStream(Encoding.UTF8.GetBytes(dataStr)); var command = new AVCommand(path, "POST", contentType: "application/json", sessionToken: user.SessionToken, stream: dataStream); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { List statisticList = new List(); List list = t.Result.Item2["results"] as List; foreach (object obj in list) { statisticList.Add(AVStatistic.Parse(obj as IDictionary)); } return statisticList; } catch (Exception e) { throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); } }); } /// /// 获取用户成绩 /// /// 成绩列表 /// 用户 /// 名称列表 public static Task> GetStatistics(AVUser user, List statisticNames = null) { if (user == null) { throw new ArgumentNullException(nameof(user)); } var path = string.Format("leaderboard/users/{0}/statistics", user.ObjectId); if (statisticNames != null && statisticNames.Count > 0) { var names = string.Join(",", statisticNames.ToArray()); path = string.Format("{0}?statistics={1}", path, names); } var sessionToken = AVUser.CurrentUser?.SessionToken; var command = new AVCommand(path, "GET", sessionToken, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { List statisticList = new List(); List list = t.Result.Item2["results"] as List; foreach (object obj in list) { statisticList.Add(AVStatistic.Parse(obj as IDictionary)); } return statisticList; } catch (Exception e) { throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); } }); } /// /// 删除用户成绩 /// /// 用户 /// 名称列表 public static Task DeleteStatistics(AVUser user, List statisticNames) { if (user == null) { throw new ArgumentNullException(nameof(user)); } if (statisticNames == null || statisticNames.Count == 0) { throw new ArgumentNullException(nameof(statisticNames)); } var path = string.Format("leaderboard/users/{0}/statistics", user.ObjectId); var names = string.Join(",", statisticNames.ToArray()); path = string.Format("{0}?statistics={1}", path, names); var command = new AVCommand(path, "DELETE", sessionToken: user.SessionToken, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command); } /// /// 获取排行榜历史数据 /// /// 排行榜归档列表 /// 跳过数量 /// 分页数量 public Task> GetArchives(int skip = 0, int limit = 10) { var path = string.Format("leaderboard/leaderboards/{0}/archives", StatisticName); path = string.Format("{0}?skip={1}&limit={2}", path, skip, limit); var command = new AVCommand(path, "GET", data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { List archives = new List(); List list = t.Result.Item2["results"] as List; foreach (object obj in list) { archives.Add(AVLeaderboardArchive.Parse(obj as IDictionary)); } return archives; }); } /// /// 获取排行榜结果 /// /// 排名列表 public Task> GetResults(int version = -1, int skip = 0, int limit = 10, List selectUserKeys = null, List includeStatistics = null) { return GetResults(null, version, skip, limit, selectUserKeys, includeStatistics); } /// /// 获取用户及附近的排名 /// /// 排名列表 /// 用户 /// 版本号 /// 跳过数量 /// 分页数量 /// 包含的玩家的字段列表 /// 包含的其他排行榜名称 public Task> GetResultsAroundUser(int version = -1, int skip = 0, int limit = 10, List selectUserKeys = null, List includeStatistics = null) { return GetResults(AVUser.CurrentUser, version, skip, limit, selectUserKeys, includeStatistics); } Task> GetResults(AVUser user, int version, int skip, int limit, List selectUserKeys, List includeStatistics) { var path = string.Format("leaderboard/leaderboards/{0}/ranks", StatisticName); if (user != null) { path = string.Format("{0}/{1}", path, user.ObjectId); } path = string.Format("{0}?skip={1}&limit={2}", path, skip, limit); if (version != -1) { path = string.Format("{0}&version={1}", path, version); } if (selectUserKeys != null) { var keys = string.Join(",", selectUserKeys.ToArray()); path = string.Format("{0}&includeUser={1}", path, keys); } if (includeStatistics != null) { var statistics = string.Join(",", includeStatistics.ToArray()); path = string.Format("{0}&includeStatistics={1}", path, statistics); } var command = new AVCommand(path, "GET", data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { List rankingList = new List(); List list = t.Result.Item2["results"] as List; foreach (object obj in list) { rankingList.Add(AVRanking.Parse(obj as IDictionary)); } return rankingList; } catch (Exception e) { throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); } }); } /// /// 设置更新策略 /// /// 排行榜对象 /// 更新策略 public Task UpdateUpdateStrategy(AVLeaderboardUpdateStrategy updateStrategy) { var data = new Dictionary { { "updateStrategy", updateStrategy.ToString().ToLower() } }; return Update(data).OnSuccess(t => { UpdateStrategy = (AVLeaderboardUpdateStrategy)Enum.Parse(typeof(AVLeaderboardUpdateStrategy), t.Result["updateStrategy"].ToString().ToUpper()); return this; }); } /// /// 设置版本更新频率 /// /// 排行榜对象 /// 版本更新频率 public Task UpdateVersionChangeInterval(AVLeaderboardVersionChangeInterval versionChangeInterval) { var data = new Dictionary { { "versionChangeInterval", versionChangeInterval.ToString().ToLower() } }; return Update(data).OnSuccess(t => { VersionChangeInterval = (AVLeaderboardVersionChangeInterval)Enum.Parse(typeof(AVLeaderboardVersionChangeInterval), t.Result["versionChangeInterval"].ToString().ToUpper()); return this; }); } Task> Update(Dictionary data) { var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); var command = new AVCommand(path, "PUT", data: data); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { return t.Result.Item2; }); } /// /// 拉取排行榜数据 /// /// 排行榜对象 public Task Fetch() { var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); var command = new AVCommand(path, "GET", data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { // 反序列化 Leaderboard 对象 var leaderboard = Parse(t.Result.Item2); return leaderboard; } catch (Exception e) { throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); } }); } /// /// 重置排行榜 /// /// 排行榜对象 public Task Reset() { var path = string.Format("leaderboard/leaderboards/{0}/incrementVersion", StatisticName); var command = new AVCommand(path, "PUT", data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).OnSuccess(t => { try { Init(t.Result.Item2); return this; } catch (Exception e) { throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); } }); } /// /// 销毁排行榜 /// public Task Destroy() { var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); var command = new AVCommand(path, "DELETE", data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command); } static AVLeaderboard Parse(IDictionary data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } var leaderboard = new AVLeaderboard(); leaderboard.Init(data); return leaderboard; } void Init(IDictionary data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } object nameObj; if (data.TryGetValue("statisticName", out nameObj)) { StatisticName = nameObj.ToString(); } object orderObj; if (data.TryGetValue("order", out orderObj)) { Order = (AVLeaderboardOrder)Enum.Parse(typeof(AVLeaderboardOrder), orderObj.ToString().ToUpper()); } object strategyObj; if (data.TryGetValue("updateStrategy", out strategyObj)) { UpdateStrategy = (AVLeaderboardUpdateStrategy)Enum.Parse(typeof(AVLeaderboardUpdateStrategy), strategyObj.ToString().ToUpper()); } object intervalObj; if (data.TryGetValue("versionChangeInterval", out intervalObj)) { VersionChangeInterval = (AVLeaderboardVersionChangeInterval)Enum.Parse(typeof(AVLeaderboardVersionChangeInterval), intervalObj.ToString().ToUpper()); } object versionObj; if (data.TryGetValue("version", out versionObj)) { Version = int.Parse(versionObj.ToString()); } } } }