diff --git a/README.md b/README.md index 1ef2684..d139baa 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Then run School of Dragons. - ApplyRewards - GetGameDataByGame (friend tab displays all players - friend filter is not yet implemented because friend lists are not implemented) - GetGameDataByGameForDateRange (friend tab displays all players) +- GetTopAchievementPointUsers (ignores type [all, buddy, hall of fame, ...] and mode [overall, monthly, weekly] properties) - GetUserAchievements (used by Magic & Mythies) - GetUserRoomList (room categories are not implemented, but it's enough for SoD) - ProcessRewardedItems (gives gems, but doesn't give gold, gold is not yet implemented) diff --git a/mitm-redirect.py b/mitm-redirect.py index 00706cc..7f23d73 100644 --- a/mitm-redirect.py +++ b/mitm-redirect.py @@ -84,6 +84,7 @@ methods = [ 'SendRawGameData', 'GetGameDataByGame', 'GetGameDataByGameForDateRange', + 'GetTopAchievementPointUsers', ] def routable(path): diff --git a/src/Controllers/Common/AchievementController.cs b/src/Controllers/Common/AchievementController.cs index 0518d58..8ba3222 100644 --- a/src/Controllers/Common/AchievementController.cs +++ b/src/Controllers/Common/AchievementController.cs @@ -204,4 +204,13 @@ public class AchievementController : Controller { return Ok(rewards); } + + [HttpPost] + [Produces("application/xml")] + [Route("V2/AchievementWebService.asmx/GetTopAchievementPointUsers")] + [VikingSession] + public IActionResult GetTopAchievementPointUsers(string request) { + UserAchievementInfoRequest infoRequest = XmlUtil.DeserializeXml(request); + return Ok(achievementService.GetTopAchievementUsers(infoRequest)); + } } diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index 7640af4..ce98a07 100644 --- a/src/Model/DBContext.cs +++ b/src/Model/DBContext.cs @@ -14,8 +14,9 @@ public class DBContext : DbContext { public DbSet MissionStates { get; set; } = null!; public DbSet Rooms { get; set; } = null!; public DbSet RoomItems { get; set; } = null!; - public DbSet GameData { get; set; } = null; - public DbSet GameDataPairs { get; set; } = null; + public DbSet GameData { get; set; } = null!; + public DbSet GameDataPairs { get; set; } = null!; + public DbSet AchievementPoints { get; set; } = null!; public string DbPath { get; } diff --git a/src/Schema/DateRange.cs b/src/Schema/DateRange.cs new file mode 100644 index 0000000..02b5c31 --- /dev/null +++ b/src/Schema/DateRange.cs @@ -0,0 +1,13 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "R", Namespace = "")] +[Serializable] +public class DateRange { + [XmlElement(ElementName = "SD")] + public DateTime? StartDate; + + [XmlElement(ElementName = "ED")] + public DateTime? EndDate; +} diff --git a/src/Schema/ModeType.cs b/src/Schema/ModeType.cs new file mode 100644 index 0000000..1e50ebe --- /dev/null +++ b/src/Schema/ModeType.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +public enum ModeType { + [XmlEnum("1")] + AllTime = 1, + [XmlEnum("2")] + Daily, + [XmlEnum("3")] + Weekly, + [XmlEnum("4")] + Monthly +} diff --git a/src/Schema/RequestType.cs b/src/Schema/RequestType.cs new file mode 100644 index 0000000..b26bb64 --- /dev/null +++ b/src/Schema/RequestType.cs @@ -0,0 +1,16 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +public enum RequestType { + [XmlEnum("1")] + All = 1, + [XmlEnum("2")] + Buddy, + [XmlEnum("3")] + Group, + [XmlEnum("4")] + Facebook, + [XmlEnum("5")] + HallOfFame +} diff --git a/src/Schema/UserAchievementInfoRequest.cs b/src/Schema/UserAchievementInfoRequest.cs new file mode 100644 index 0000000..78038f8 --- /dev/null +++ b/src/Schema/UserAchievementInfoRequest.cs @@ -0,0 +1,31 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "AREQ", Namespace = "")] +[Serializable] +public class UserAchievementInfoRequest { + [XmlElement(ElementName = "PID")] + public int ProductGroupID; + + [XmlElement(ElementName = "UID")] + public Guid UserID; + + [XmlElement(ElementName = "PTID")] + public int PointTypeID; + + [XmlElement(ElementName = "T")] + public RequestType Type; + + [XmlElement(ElementName = "M")] + public ModeType Mode; + + [XmlElement(ElementName = "P")] + public int Page; + + [XmlElement(ElementName = "Q")] + public int Quantity; + + [XmlElement(ElementName = "FBIDS")] + public List FacebookUserIDs; +} diff --git a/src/Schema/UserAchievementInfoResponse.cs b/src/Schema/UserAchievementInfoResponse.cs new file mode 100644 index 0000000..5308cac --- /dev/null +++ b/src/Schema/UserAchievementInfoResponse.cs @@ -0,0 +1,13 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "UAIR", Namespace = "")] +[Serializable] +public class UserAchievementInfoResponse { + [XmlElement(ElementName = "UAI")] + public UserAchievementInfo[] AchievementInfo; + + [XmlElement(ElementName = "DR")] + public DateRange DateRange; +} diff --git a/src/Services/AchievementService.cs b/src/Services/AchievementService.cs index dcbbbf8..a2cd206 100644 --- a/src/Services/AchievementService.cs +++ b/src/Services/AchievementService.cs @@ -9,10 +9,12 @@ namespace sodoff.Services { public class AchievementService { private AchievementStoreSingleton achievementStore; private InventoryService inventoryService; + public readonly DBContext ctx; - public AchievementService(AchievementStoreSingleton achievementStore, InventoryService inventoryService) { + public AchievementService(AchievementStoreSingleton achievementStore, InventoryService inventoryService, DBContext ctx) { this.achievementStore = achievementStore; this.inventoryService = inventoryService; + this.ctx = ctx; } public UserAchievementInfo CreateUserAchievementInfo(Guid userId, int? value, AchievementPointTypes type) { @@ -162,5 +164,29 @@ namespace sodoff.Services { UserID = viking.Uid }; } + + public UserAchievementInfoResponse GetTopAchievementUsers(UserAchievementInfoRequest request) { + // TODO: Type and mode are currently ignored + List achievementInfo = new(); + var topAchievers = ctx.AchievementPoints.Where(x => x.Type == request.PointTypeID) + .Select(e => new { e.Viking.Uid, e.Viking.Name, e.Value }) + .Skip((request.Page - 1) * request.Quantity) + .Take(request.Quantity) + .OrderByDescending(e => e.Value); + + foreach (var a in topAchievers) { + achievementInfo.Add(new UserAchievementInfo { + UserID = a.Uid, + UserName = a.Name, + AchievementPointTotal = a.Value, + PointTypeID = (AchievementPointTypes)request.PointTypeID + }); + } + + return new UserAchievementInfoResponse { + AchievementInfo = achievementInfo.ToArray(), + DateRange = new DateRange() + }; + } } }