From 1c01eb25f5f3bd136dd8597298c925a30bc4e3c3 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Wed, 12 Jul 2023 22:07:24 +0200 Subject: [PATCH] hideouts --- mitm-redirect.py | 5 +- src/Controllers/Common/ContentController.cs | 44 ++++++++- src/Controllers/Common/RatingController.cs | 21 +++++ .../Common/RegistrationController.cs | 9 +- src/Model/DBContext.cs | 18 +++- src/Model/Room.cs | 16 ++++ src/Model/RoomItem.cs | 13 +++ src/Model/Viking.cs | 1 + src/Program.cs | 1 + src/Schema/ItemPositionValidationResult.cs | 20 ++++ src/Schema/UserItemPosition.cs | 57 ++++++++++++ src/Schema/UserItemPositionList.cs | 11 +++ src/Schema/UserItemPositionSetRequest.cs | 10 ++ src/Schema/UserItemPositionSetResponse.cs | 19 ++++ src/Schema/UserItemStat.cs | 13 +++ src/Schema/UserItemState.cs | 21 +++++ src/Services/RoomService.cs | 91 +++++++++++++++++++ 17 files changed, 364 insertions(+), 6 deletions(-) create mode 100644 src/Controllers/Common/RatingController.cs create mode 100644 src/Model/Room.cs create mode 100644 src/Model/RoomItem.cs create mode 100644 src/Schema/ItemPositionValidationResult.cs create mode 100644 src/Schema/UserItemPosition.cs create mode 100644 src/Schema/UserItemPositionList.cs create mode 100644 src/Schema/UserItemPositionSetRequest.cs create mode 100644 src/Schema/UserItemPositionSetResponse.cs create mode 100644 src/Schema/UserItemStat.cs create mode 100644 src/Schema/UserItemState.cs create mode 100644 src/Services/RoomService.cs diff --git a/mitm-redirect.py b/mitm-redirect.py index d72581a..46c9877 100644 --- a/mitm-redirect.py +++ b/mitm-redirect.py @@ -57,7 +57,10 @@ methods = [ 'GetUserMissionState', 'SetAchievementAndGetReward', 'SetUserAchievementTask', - 'GetAnnouncementsByUser' + 'GetAnnouncementsByUser', + 'GetUserRoomItemPositions', + 'SetUserRoomItemPositions', + 'GetAverageRatingForRoom' ] def routable(path): diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index 76d4928..5339983 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -14,11 +14,13 @@ public class ContentController : Controller { private KeyValueService keyValueService; private ItemService itemService; private MissionService missionService; - public ContentController(DBContext ctx, KeyValueService keyValueService, ItemService itemService, MissionService missionService) { + private RoomService roomService; + public ContentController(DBContext ctx, KeyValueService keyValueService, ItemService itemService, MissionService missionService, RoomService roomService) { this.ctx = ctx; this.keyValueService = keyValueService; this.itemService = itemService; this.missionService = missionService; + this.roomService = roomService; } [HttpPost] @@ -149,7 +151,7 @@ public class ContentController : Controller { if (item.Quantity == 0) continue; // Don't include an item that the viking doesn't have ItemData itemData = itemService.GetItem(item.ItemId); UserItemData uid = new UserItemData { - UserInventoryID = viking.Inventory.Id, + UserInventoryID = item.Id, ItemID = itemData.ItemID, Quantity = item.Quantity, Uses = itemData.Uses, @@ -656,6 +658,44 @@ public class ContentController : Controller { return Ok(response); } + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetUserRoomItemPositions")] + public IActionResult GetUserRoomItemPositions([FromForm] string apiToken, [FromForm] string roomID) { + Room? room = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.FirstOrDefault(x => x.RoomId == roomID); + if (room is null) + return Ok(); + return Ok(roomService.GetUserItemPositionList(room)); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetUserRoomItemPositions")] + public IActionResult SetUserRoomItemPositions([FromForm] string apiToken, [FromForm] string createXml, [FromForm] string updateXml, [FromForm] string removeXml, [FromForm] string roomID) { + Room? room = ctx.Sessions.FirstOrDefault(e => e.ApiToken == apiToken)?.Viking?.Rooms.FirstOrDefault(x => x.RoomId == roomID); + if (room is null) + return Ok(); + + UserItemPositionSetRequest[] createItems = XmlUtil.DeserializeXml(createXml); + UserItemPositionSetRequest[] updateItems = XmlUtil.DeserializeXml(updateXml); + int[] deleteItems = XmlUtil.DeserializeXml(removeXml); + + int[] ids = roomService.CreateItems(createItems, room); + UserItemState[] state = roomService.UpdateItems(updateItems, room); + roomService.DeleteItems(deleteItems, room); + + UserItemPositionSetResponse response = new UserItemPositionSetResponse { + Success = true, + CreatedUserItemPositionIDs = ids, + Result = ItemPositionValidationResult.Valid + }; + + if (state.Length > 0) + response.UserItemStates = state; + + return Ok(response); + } + private RaisedPetData GetRaisedPetDataFromDragon (Dragon dragon) { RaisedPetData data = XmlUtil.DeserializeXml(dragon.RaisedPetData); data.RaisedPetID = dragon.Id; diff --git a/src/Controllers/Common/RatingController.cs b/src/Controllers/Common/RatingController.cs new file mode 100644 index 0000000..2ade5db --- /dev/null +++ b/src/Controllers/Common/RatingController.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using sodoff.Model; +using sodoff.Schema; +using sodoff.Util; + +namespace sodoff.Controllers.Common; + +public class RatingController : Controller +{ + + [HttpPost] + [Produces("application/xml")] + [Route("V2/Ratingwebservice.asmx/GetAverageRatingForRoom")] + public IActionResult GetAverageRatingForRoom([FromForm] string apiToken, [FromForm] string request) + { + // TODO: This is a placeholder + return Ok(5); + } + +} diff --git a/src/Controllers/Common/RegistrationController.cs b/src/Controllers/Common/RegistrationController.cs index e988462..0e92e3f 100644 --- a/src/Controllers/Common/RegistrationController.cs +++ b/src/Controllers/Common/RegistrationController.cs @@ -13,11 +13,13 @@ public class RegistrationController : Controller { private readonly DBContext ctx; private ItemService itemService; private MissionService missionService; + private RoomService roomService; - public RegistrationController(DBContext ctx, ItemService itemService, MissionService missionService) { + public RegistrationController(DBContext ctx, ItemService itemService, MissionService missionService, RoomService roomService) { this.ctx = ctx; this.itemService = itemService; this.missionService = missionService; + this.roomService = roomService; } [HttpPost] @@ -90,7 +92,8 @@ public class RegistrationController : Controller { Id = Guid.NewGuid().ToString(), Name = data.ChildName, User = user, - Inventory = inv + Inventory = inv, + Rooms = new List() }; missionService.SetUpMissions(v); @@ -98,6 +101,8 @@ public class RegistrationController : Controller { ctx.Vikings.Add(v); ctx.SaveChanges(); + roomService.CreateRoom(v, "MyRoomINT"); + return Ok(new RegistrationResult { UserID = v.Id, Status = MembershipUserStatus.Success diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index f66b6f6..6636393 100644 --- a/src/Model/DBContext.cs +++ b/src/Model/DBContext.cs @@ -12,6 +12,9 @@ public class DBContext : DbContext { public DbSet TaskStatuses { get; set; } = null!; public DbSet Inventories { get; set; } = null!; public DbSet InventoryItems { get; set; } = null!; + public DbSet MissionStates { get; set; } = null!; + public DbSet Rooms { get; set; } = null!; + public DbSet RoomItems { get; set; } = null!; public string DbPath { get; } @@ -40,6 +43,9 @@ public class DBContext : DbContext { builder.Entity().HasMany(v => v.MissionStates) .WithOne(e => e.Viking); + builder.Entity().HasMany(v => v.Rooms) + .WithOne(e => e.Viking); + builder.Entity().HasOne(s => s.User) .WithMany(e => e.Vikings) .HasForeignKey(e => e.UserId); @@ -113,6 +119,16 @@ public class DBContext : DbContext { builder.Entity().HasOne(m => m.Viking) .WithMany(e => e.MissionStates) .HasForeignKey(e => e.VikingId); - + + builder.Entity().HasOne(r => r.Viking) + .WithMany(e => e.Rooms) + .HasForeignKey(e => e.VikingId); + + builder.Entity().HasMany(r => r.Items) + .WithOne(e => e.Room); + + builder.Entity().HasOne(i => i.Room) + .WithMany(r => r.Items) + .HasForeignKey(e => e.RoomId); } } diff --git a/src/Model/Room.cs b/src/Model/Room.cs new file mode 100644 index 0000000..d7be8d3 --- /dev/null +++ b/src/Model/Room.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace sodoff.Model; + +public class Room { + [Key] + public int Id { get; set; } + + public string RoomId { get; set; } + + public string VikingId { get; set; } = null!; + + public virtual Viking? Viking { get; set; } + + public virtual ICollection Items { get; set; } = null!; +} \ No newline at end of file diff --git a/src/Model/RoomItem.cs b/src/Model/RoomItem.cs new file mode 100644 index 0000000..329b0bd --- /dev/null +++ b/src/Model/RoomItem.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace sodoff.Model; +public class RoomItem { + [Key] + public int Id { get; set; } + + public int RoomId { get; set; } + + public virtual Room Room { get; set; } + + public string RoomItemData { get; set; } +} diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index 39e1b98..fa3ba14 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -20,6 +20,7 @@ public class Viking { public virtual ICollection Dragons { get; set; } = null!; public virtual ICollection Images { get; set; } = null!; public virtual ICollection MissionStates { get; set; } = null!; + public virtual ICollection Rooms { get; set; } = null!; public virtual Dragon? SelectedDragon { get; set; } public int InventoryId { get; set; } diff --git a/src/Program.cs b/src/Program.cs index 6ecac06..65ea233 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -17,6 +17,7 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddSingleton(); +builder.Services.AddScoped(); var app = builder.Build(); diff --git a/src/Schema/ItemPositionValidationResult.cs b/src/Schema/ItemPositionValidationResult.cs new file mode 100644 index 0000000..881c907 --- /dev/null +++ b/src/Schema/ItemPositionValidationResult.cs @@ -0,0 +1,20 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +public enum ItemPositionValidationResult { + [XmlEnum("1")] + Valid = 1, + [XmlEnum("2")] + PositionIDInNewItem, + [XmlEnum("3")] + PositionIDInvalid, + [XmlEnum("4")] + ParentIndexOutofRange, + [XmlEnum("5")] + ParentIndexInvalid, + [XmlEnum("6")] + CommonInventoryIDInvalid, + [XmlEnum("7")] + ParentIDInvalid +} diff --git a/src/Schema/UserItemPosition.cs b/src/Schema/UserItemPosition.cs new file mode 100644 index 0000000..ce75e00 --- /dev/null +++ b/src/Schema/UserItemPosition.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlInclude(typeof(UserItemPositionSetRequest))] +[XmlRoot(ElementName = "UIP", Namespace = "")] +[Serializable] +public class UserItemPosition { + [XmlElement(ElementName = "iid")] + public int? ItemID { get; set; } + + [XmlElement(ElementName = "uses")] + public int? Uses { get; set; } + + [XmlElement(ElementName = "invmdate")] + public DateTime InvLastModifiedDate { get; set; } + + [XmlElement(ElementName = "uis")] + public UserItemState UserItemState { get; set; } + + [XmlElement(ElementName = "uia", IsNullable = true)] + public PairData UserItemAttributes { get; set; } + + [XmlElement(ElementName = "uiss", IsNullable = true)] + public UserItemStat UserItemStat { get; set; } + + [XmlElement(ElementName = "id", IsNullable = true)] + public int? UserItemPositionID; + + [XmlElement(ElementName = "uicid")] + public int? UserInventoryCommonID; + + [XmlElement(ElementName = "i")] + public ItemData Item; + + [XmlElement(ElementName = "px")] + public double? PositionX; + + [XmlElement(ElementName = "py")] + public double? PositionY; + + [XmlElement(ElementName = "pz")] + public double? PositionZ; + + [XmlElement(ElementName = "rx")] + public double? RotationX; + + [XmlElement(ElementName = "ry")] + public double? RotationY; + + [XmlElement(ElementName = "rz")] + public double? RotationZ; + + [XmlElement(ElementName = "pid", IsNullable = true)] + public int? ParentID; +} diff --git a/src/Schema/UserItemPositionList.cs b/src/Schema/UserItemPositionList.cs new file mode 100644 index 0000000..19d61fd --- /dev/null +++ b/src/Schema/UserItemPositionList.cs @@ -0,0 +1,11 @@ + +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "ArrayOfUserItemPosition", Namespace = "http://api.jumpstart.com/")] +[Serializable] +public class UserItemPositionList { + [XmlElement(ElementName = "UserItemPosition")] + public UserItemPosition[] UserItemPosition; +} diff --git a/src/Schema/UserItemPositionSetRequest.cs b/src/Schema/UserItemPositionSetRequest.cs new file mode 100644 index 0000000..2505b42 --- /dev/null +++ b/src/Schema/UserItemPositionSetRequest.cs @@ -0,0 +1,10 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "UIPSR", Namespace = "")] +[Serializable] +public class UserItemPositionSetRequest : UserItemPosition { + [XmlElement(ElementName = "pix")] + public int? ParentIndex; +} diff --git a/src/Schema/UserItemPositionSetResponse.cs b/src/Schema/UserItemPositionSetResponse.cs new file mode 100644 index 0000000..8874ed5 --- /dev/null +++ b/src/Schema/UserItemPositionSetResponse.cs @@ -0,0 +1,19 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "UIPSRS", Namespace = "")] +[Serializable] +public class UserItemPositionSetResponse { + [XmlElement(ElementName = "s")] + public bool Success; + + [XmlElement(ElementName = "ids")] + public int[] CreatedUserItemPositionIDs; + + [XmlElement(ElementName = "r")] + public ItemPositionValidationResult Result; + + [XmlElement(ElementName = "uciis")] + public UserItemState[] UserItemStates; +} diff --git a/src/Schema/UserItemStat.cs b/src/Schema/UserItemStat.cs new file mode 100644 index 0000000..2264fbb --- /dev/null +++ b/src/Schema/UserItemStat.cs @@ -0,0 +1,13 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "UISS", Namespace = "")] +[Serializable] +public class UserItemStat { + [XmlElement(ElementName = "iss", IsNullable = true)] + public ItemStat[] ItemStats { get; set; } + + [XmlElement(ElementName = "it", IsNullable = true)] + public ItemTier? ItemTier { get; set; } +} diff --git a/src/Schema/UserItemState.cs b/src/Schema/UserItemState.cs new file mode 100644 index 0000000..23da4d6 --- /dev/null +++ b/src/Schema/UserItemState.cs @@ -0,0 +1,21 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[Serializable] +public class UserItemState { + [XmlElement(ElementName = "CIID")] + public int CommonInventoryID; + + [XmlElement(ElementName = "UIPID")] + public int UserItemPositionID; + + [XmlElement(ElementName = "IID")] + public int ItemID; + + [XmlElement(ElementName = "ISID")] + public int ItemStateID; + + [XmlElement(ElementName = "SCD")] + public DateTime StateChangeDate; +} diff --git a/src/Services/RoomService.cs b/src/Services/RoomService.cs new file mode 100644 index 0000000..a32164f --- /dev/null +++ b/src/Services/RoomService.cs @@ -0,0 +1,91 @@ +using sodoff.Model; +using sodoff.Schema; +using sodoff.Util; +using System.Reflection; +using System.Xml; +using System.Xml.Linq; + +namespace sodoff.Services; +public class RoomService { + + private readonly DBContext ctx; + + public RoomService(DBContext ctx) { + this.ctx = ctx; + } + + public void CreateRoom(Viking viking, string roomId) { + viking.Rooms.Add(new Room { RoomId = roomId }); + ctx.SaveChanges(); + } + + public int[] CreateItems(UserItemPositionSetRequest[] roomItemRequest, Room room) { + List ids = new(); + foreach (var itemRequest in roomItemRequest) { + // TODO: Remove item from inventory (using CommonInventoryID) + InventoryItem? i = room.Viking?.Inventory.InventoryItems.FirstOrDefault(x => x.Id == itemRequest.UserInventoryCommonID); + if (i != null) i.Quantity--; + UserItemPosition uip = itemRequest; + RoomItem roomItem = new RoomItem { + RoomItemData = XmlUtil.SerializeXml(itemRequest).Replace(" xsi:type=\"UserItemPositionSetRequest\"", "") // NOTE: No way to avoid this hack when we're serializing a child class into a base class + }; + + room.Items.Add(roomItem); + ctx.SaveChanges(); + ids.Add(roomItem.Id); + } + return ids.ToArray(); + } + + public UserItemState[] UpdateItems(UserItemPositionSetRequest[] roomItemRequest, Room room) { + List state = new(); + foreach (var itemRequest in roomItemRequest) { + RoomItem? item = room.Items.FirstOrDefault(x => x.Id == itemRequest.UserItemPositionID); + if (item is null) continue; + + UserItemPosition itemPosition = XmlUtil.DeserializeXml(item.RoomItemData); + + if (itemRequest.Uses != null) itemPosition.Uses = itemRequest.Uses; + itemPosition.InvLastModifiedDate = itemRequest.InvLastModifiedDate; + if (itemRequest.UserItemState != null) itemPosition.UserItemState = itemRequest.UserItemState; + if (itemRequest.UserItemAttributes != null) itemPosition.UserItemAttributes = itemRequest.UserItemAttributes; + if (itemRequest.UserItemStat != null) itemPosition.UserItemStat = itemRequest.UserItemStat; + if (itemRequest.Item != null) itemPosition.Item = itemRequest.Item; + if (itemRequest.PositionX != null) itemPosition.PositionX = itemRequest.PositionX; + if (itemRequest.PositionY != null) itemPosition.PositionY = itemRequest.PositionY; + if (itemRequest.PositionZ != null) itemPosition.PositionZ = itemRequest.PositionZ; + if (itemRequest.RotationX != null) itemPosition.RotationX = itemRequest.RotationX; + if (itemRequest.RotationY != null) itemPosition.RotationY = itemRequest.RotationY; + if (itemRequest.RotationZ != null) itemPosition.RotationZ = itemRequest.RotationZ; + if (itemRequest.ParentID != null) itemPosition.ParentID = itemRequest.ParentID; + + item.RoomItemData = XmlUtil.SerializeXml(itemPosition); + if (itemPosition.UserItemState != null) state.Add(itemPosition.UserItemState); + } + + ctx.SaveChanges(); + return state.ToArray(); + } + + public void DeleteItems(int[] itemIds, Room room) { + for (int i = 0; i < itemIds.Length; i++) { + RoomItem? ri = room.Items.FirstOrDefault(x => x.Id == itemIds[i]); + if (ri is null) continue; + UserItemPosition itemPosition = XmlUtil.DeserializeXml(ri.RoomItemData); + room.Items.Remove(ri); + InventoryItem? invItem = room.Viking?.Inventory.InventoryItems.FirstOrDefault(x => x.Id == itemPosition.UserInventoryCommonID); + if (invItem != null) invItem.Quantity++; + } + ctx.SaveChanges(); + } + + public UserItemPositionList GetUserItemPositionList(Room room) { + List itemPosition = new(); + foreach (var item in room.Items) { + UserItemPosition data = XmlUtil.DeserializeXml(item.RoomItemData); + data.UserItemPositionID = item.Id; + itemPosition.Add(data); + } + return new UserItemPositionList { UserItemPosition = itemPosition.ToArray() }; + } +}