From 9993198a9be5500a7eb54f0d0b2d030d4ae107f0 Mon Sep 17 00:00:00 2001 From: meleestars <122710663+meleestars@users.noreply.github.com> Date: Wed, 10 Jul 2024 10:09:20 +0200 Subject: [PATCH] Implemented neighborhoods, fixed default houses Also: * implemented ``GetAvatarByUserID`` from @Moonbase's previous PR. * implemented ``GetPeriodicGameDataByGame`` and ``GetGamePlayDataForDateRange`` --------- Co-authored-by: Alan Moon --- src/Controllers/Common/ContentController.cs | 63 +++++++- src/Controllers/Common/RatingController.cs | 9 +- src/Model/DBContext.cs | 11 ++ src/Model/Neighborhood.cs | 33 +++++ src/Model/Viking.cs | 1 + src/Program.cs | 1 + src/Resources/defaulthouse.xml | 151 ++++++++++++++++++++ src/Schema/ArrayOfGamePlayData.cs | 11 ++ src/Schema/GamePlayData.cs | 14 ++ src/Schema/Neighbor.cs | 14 ++ src/Schema/NeighborData.cs | 14 ++ src/Services/NeighborhoodService.cs | 94 ++++++++++++ src/sodoff.csproj | 4 + 13 files changed, 410 insertions(+), 10 deletions(-) create mode 100644 src/Model/Neighborhood.cs create mode 100644 src/Resources/defaulthouse.xml create mode 100644 src/Schema/ArrayOfGamePlayData.cs create mode 100644 src/Schema/GamePlayData.cs create mode 100644 src/Schema/Neighbor.cs create mode 100644 src/Schema/NeighborData.cs create mode 100644 src/Services/NeighborhoodService.cs diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index 7c674d8..fda1135 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -23,10 +23,23 @@ public class ContentController : Controller { private InventoryService inventoryService; private GameDataService gameDataService; private DisplayNamesService displayNamesService; + private NeighborhoodService neighborhoodService; private Random random = new Random(); private readonly IOptions config; - public ContentController(DBContext ctx, KeyValueService keyValueService, ItemService itemService, MissionService missionService, RoomService roomService, AchievementService achievementService, InventoryService inventoryService, GameDataService gameDataService, DisplayNamesService displayNamesService, IOptions config) { + public ContentController( + DBContext ctx, + KeyValueService keyValueService, + ItemService itemService, + MissionService missionService, + RoomService roomService, + AchievementService achievementService, + InventoryService inventoryService, + GameDataService gameDataService, + DisplayNamesService displayNamesService, + NeighborhoodService neighborhoodService, + IOptions config + ) { this.ctx = ctx; this.keyValueService = keyValueService; this.itemService = itemService; @@ -36,6 +49,7 @@ public class ContentController : Controller { this.inventoryService = inventoryService; this.gameDataService = gameDataService; this.displayNamesService = displayNamesService; + this.neighborhoodService = neighborhoodService; this.config = config; } @@ -426,6 +440,20 @@ public class ContentController : Controller { return Ok(avatarData); } + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetAvatarByUserID")] // used by World Of Jumpstart, only for public information + public IActionResult GetAvatarByUserId([FromForm] Guid userId) + { + Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Uid == userId); + AvatarData avatarData = XmlUtil.DeserializeXml(viking.AvatarSerialized); + + avatarData.Id = viking.Id; + + if (viking != null && avatarData != null) return Ok(avatarData); + else return Ok(new AvatarData()); + } + [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetAvatar")] // used by World Of Jumpstart @@ -1598,7 +1626,7 @@ public class ContentController : Controller { ); if (ret != null) return Ok(ret); - return Ok(""); + return Ok(XmlUtil.ReadResourceXmlString("defaulthouse")); } [HttpPost] @@ -1658,6 +1686,21 @@ public class ContentController : Controller { return Ok(true); } + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/SetNeighbor")] // used by World Of Jumpstart + [VikingSession(UseLock=true)] + public IActionResult SetNeighbor(Viking viking, string neighboruserid, int slot) { + return Ok(neighborhoodService.SaveNeighbors(viking, neighboruserid, slot)); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetNeighborsByUserID")] // used by World Of Jumpstart + public IActionResult GetNeighborsByUserID(string userId) { + return Ok(neighborhoodService.GetNeighbors(userId)); + } + [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/GetGameData")] @@ -2096,10 +2139,18 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] - [Route("ContentWebService.asmx/GetPeriodicGameDataByGame")] // used by Math Blaster - public IActionResult GetPeriodicGameDataByGame() { - // TODO: This is a placeholder - return Ok(new GameDataSummary()); + [Route("ContentWebService.asmx/GetPeriodicGameDataByGame")] // used by Math Blaster and WoJS (probably from 24 hours ago to now) + [VikingSession(UseLock = true)] + public IActionResult GetPeriodicGameDataByGame(Viking viking, [FromForm] int gameId, bool isMultiplayer, int difficulty, int gameLevel, string key, int count, bool AscendingOrder, int score, bool buddyFilter, string apiKey) { + return Ok(gameDataService.GetGameData(viking, gameId, isMultiplayer, difficulty, gameLevel, key, count, AscendingOrder, buddyFilter, apiKey, DateTime.Now.AddHours(-24), DateTime.Now)); + } + + [HttpPost] + [Produces("application/xml")] + [Route("ContentWebService.asmx/GetGamePlayDataForDateRange")] // used by WoJS + public IActionResult GetGamePlayDataForDateRange(Viking viking, string startDate, string endDate) { + // stub, didn't work for some reason, even with the correct response + return Ok(new ArrayOfGamePlayData()); } [HttpPost] diff --git a/src/Controllers/Common/RatingController.cs b/src/Controllers/Common/RatingController.cs index da971bd..ef18d4d 100644 --- a/src/Controllers/Common/RatingController.cs +++ b/src/Controllers/Common/RatingController.cs @@ -8,13 +8,14 @@ namespace sodoff.Controllers.Common; public class RatingController : Controller { - [HttpPost] [Produces("application/xml")] [Route("MissionWebService.asmx/GetPayout")] // used by World Of Jumpstart - public IActionResult GetPayout([FromForm] int points) { - // TODO - placeholder - return Ok(points / 100); + public IActionResult GetPayout([FromForm] int points, [FromForm] string ModuleName) { + // TODO: better calculations, improve module determination code + // for now, a trusty placeholder + + return Ok(points / (350 / 3)); } [HttpPost] diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index 089c9b7..c72f7c0 100644 --- a/src/Model/DBContext.cs +++ b/src/Model/DBContext.cs @@ -23,6 +23,9 @@ public class DBContext : DbContext { public DbSet ProfileAnswers { get; set; } = null!; public DbSet MMORoles { get; set; } = null!; public DbSet Parties { get; set; } = null!; + public DbSet Neighborhoods { get; set; } = null!; + // we had a brief debate on whether it's neighborhoods or neighborheed + private readonly IOptions config; public DBContext(IOptions config) { @@ -130,6 +133,9 @@ public class DBContext : DbContext { builder.Entity().HasMany(v => v.MMORoles) .WithOne(e => e.Viking); + builder.Entity().HasOne(v => v.Neighborhood) + .WithOne(e => e.Viking); + // Dragons builder.Entity().HasOne(d => d.Viking) .WithMany(e => e.Dragons) @@ -241,5 +247,10 @@ public class DBContext : DbContext { builder.Entity().HasOne(r => r.Viking) .WithMany(e => e.MMORoles) .HasForeignKey(e => e.VikingId); + + // Neighborhoods + builder.Entity().HasOne(r => r.Viking) + .WithOne(e => e.Neighborhood) + .HasForeignKey(e => e.VikingId); } } diff --git a/src/Model/Neighborhood.cs b/src/Model/Neighborhood.cs new file mode 100644 index 0000000..a748c76 --- /dev/null +++ b/src/Model/Neighborhood.cs @@ -0,0 +1,33 @@ +using sodoff.Schema; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Diagnostics.CodeAnalysis; + +namespace sodoff.Model +{ + public class Neighborhood + { + public virtual Viking? Viking { get; set; } + + [Key] + public int Id { get; set; } + + [Required] + public int VikingId { get; set; } + + [Required] + public Guid Slot0 { get; set; } + + [Required] + public Guid Slot1 { get; set; } + + [Required] + public Guid Slot2 { get; set; } + + [Required] + public Guid Slot3 { get; set; } + + [Required] + public Guid Slot4 { get; set; } + } +} diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index 8777b75..ff8bc93 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -37,6 +37,7 @@ public class Viking { public virtual ICollection SavedData { get; set; } = null!; public virtual ICollection Parties { get; set; } = null!; public virtual ICollection MMORoles { get; set; } = null!; + public virtual Neighborhood? Neighborhood { get; set; } = null!; public virtual Dragon? SelectedDragon { get; set; } public DateTime? CreationDate { get; set; } diff --git a/src/Program.cs b/src/Program.cs index b374bb4..1eca9c4 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -38,6 +38,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); bool assetServer = builder.Configuration.GetSection("AssetServer").GetValue("Enabled"); string assetIP = builder.Configuration.GetSection("AssetServer").GetValue("ListenIP"); diff --git a/src/Resources/defaulthouse.xml b/src/Resources/defaulthouse.xml new file mode 100644 index 0000000..4ac5e47 --- /dev/null +++ b/src/Resources/defaulthouse.xml @@ -0,0 +1,151 @@ + + + + Foundation_GEO + RS_SHARED/MyHouseFoundations01.unity3d/PfFoundationCottage + + + Foundation_STL + RS_SHARED/MyHouseFoundations01.unity3d/StyleFoundationsCottageLogTex + + + Foundation_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Foundation_GLS + RS_SHARED/MyHouseGlass01.unity3d/GlassBlueTex + + + Foundation_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + Stairs_GEO + RS_SHARED/MyHouseStairs01.unity3d/PfStairCottage + + + Stairs_STL + RS_SHARED/MyHouseStairs01.unity3d/StyleStairsCottageLogTex + + + Stairs_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Stairs_GLS + EMPTY + + + Stairs_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + Wall_GEO + RS_SHARED/MyHouseWalls01.unity3d/PfWallCottage + + + Wall_STL + RS_SHARED/MyHouseWalls01.unity3d/StyleWallsCottageLogTex + + + Wall_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Wall_GLS + EMPTY + + + Wall_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + Roof_GEO + RS_SHARED/MyHouseRoofs01.unity3d/PfRoofCottage + + + Roof_STL + RS_SHARED/MyHouseRoofs01.unity3d/StyleRoofsCottageHauntedTex + + + Roof_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Roof_GLS + RS_SHARED/MyHouseGlass01.unity3d/GlassBlueTex + + + Roof_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + Window_GEO + RS_SHARED/MyHouseWindows01.unity3d/PfWindowCottage + + + Window_STL + RS_SHARED/MyHouseWindows01.unity3d/StyleWindowsCottageLogTex + + + Window_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Window_GLS + RS_SHARED/MyHouseGlass01.unity3d/GlassBlueTex + + + Window_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + Door_GEO + RS_SHARED/MyHouseDoors01.unity3d/PfDoorCottage + + + Door_STL + RS_SHARED/MyHouseDoors01.unity3d/StyleDoorsCottageLogTex + + + Door_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Door_GLS + RS_SHARED/MyHouseGlass01.unity3d/GlassBlueTex + + + Door_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + Chimney_GEO + RS_SHARED/MyHouseChimneys01.unity3d/PfChimneyCottage + + + Chimney_STL + RS_SHARED/MyHouseChimneys01.unity3d/StyleChimneysCottageHauntedTex + + + Chimney_SKN + RS_SHARED/MyHouseSkin01.unity3d/SkinCastleClassicTex + + + Chimney_GLS + EMPTY + + + Chimney_TRM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + + DEFAULT_GLASS + RS_SHARED/MyHouseGlass01.unity3d/GlassBlueTex + + + DEFAULT_TRIM + RS_SHARED/MyHouseTrims01.unity3d/TrimStoneIvyTex + + \ No newline at end of file diff --git a/src/Schema/ArrayOfGamePlayData.cs b/src/Schema/ArrayOfGamePlayData.cs new file mode 100644 index 0000000..4893273 --- /dev/null +++ b/src/Schema/ArrayOfGamePlayData.cs @@ -0,0 +1,11 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "ArrayOfGamePlayData", Namespace = "")] +[Serializable] +public class ArrayOfGamePlayData +{ + [XmlElement(ElementName = "GamePlayData", IsNullable = true)] + public GamePlayData[]? GamePlayData; +} diff --git a/src/Schema/GamePlayData.cs b/src/Schema/GamePlayData.cs new file mode 100644 index 0000000..f317f28 --- /dev/null +++ b/src/Schema/GamePlayData.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "GamePlayData", Namespace = "")] +[Serializable] +public class GamePlayData +{ + [XmlElement(ElementName = "GMID")] // Game ID + public int GMID; + + [XmlElement(ElementName = "PLCT")] // presumably Player Count + public int PLCT; +} diff --git a/src/Schema/Neighbor.cs b/src/Schema/Neighbor.cs new file mode 100644 index 0000000..8c0f31f --- /dev/null +++ b/src/Schema/Neighbor.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "Neighbor", Namespace = "")] +[Serializable] +public class Neighbor +{ + [XmlElement(ElementName = "NeighborUserID")] + public Guid NeighborUserID; + + [XmlElement(ElementName = "Slot")] + public int Slot; +} \ No newline at end of file diff --git a/src/Schema/NeighborData.cs b/src/Schema/NeighborData.cs new file mode 100644 index 0000000..ddcabe5 --- /dev/null +++ b/src/Schema/NeighborData.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "NeighborData", Namespace = "")] +[Serializable] +public class NeighborData +{ + [XmlElement(ElementName = "UserID")] + public Guid UserID; + + [XmlElement(ElementName = "Neighbors")] + public Neighbor[] Neighbors; +} \ No newline at end of file diff --git a/src/Services/NeighborhoodService.cs b/src/Services/NeighborhoodService.cs new file mode 100644 index 0000000..8bec07c --- /dev/null +++ b/src/Services/NeighborhoodService.cs @@ -0,0 +1,94 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using sodoff.Configuration; +using sodoff.Model; +using sodoff.Schema; +using sodoff.Util; + +namespace sodoff.Services +{ + public class NeighborhoodService + { + private readonly DBContext ctx; + + // default neighborhood slots (NPCs) + Guid slot0 = new Guid("aaaaaaaa-0000-0000-0000-000000000000"); + Guid slot1 = new Guid("bbbbbbbb-0000-0000-0000-000000000000"); + Guid slot2 = new Guid("cccccccc-0000-0000-0000-000000000000"); + Guid slot3 = new Guid("dddddddd-0000-0000-0000-000000000000"); + Guid slot4 = new Guid("eeeeeeee-0000-0000-0000-000000000000"); + + public NeighborhoodService(DBContext ctx) { + this.ctx = ctx; + } + + public bool SaveNeighbors(Viking viking, string neighborUid, int slot) { + Model.Neighborhood? neighborhood = viking.Neighborhood; + + if (neighborhood == null) // if viking has no neighborhood yet, create a default one + viking.Neighborhood = new Model.Neighborhood { + VikingId = viking.Id, + Slot0 = this.slot0, + Slot1 = this.slot1, + Slot2 = this.slot2, + Slot3 = this.slot3, + Slot4 = this.slot4 + }; + + // couldn't find a better way to do this + switch (slot) { + case 0: + viking.Neighborhood.Slot0 = new Guid(neighborUid); + break; + case 1: + viking.Neighborhood.Slot1 = new Guid(neighborUid); + break; + case 2: + viking.Neighborhood.Slot2 = new Guid(neighborUid); + break; + case 3: + viking.Neighborhood.Slot3 = new Guid(neighborUid); + break; + case 4: + viking.Neighborhood.Slot4 = new Guid(neighborUid); + break; + } + + ctx.SaveChanges(); + return true; + } + + public NeighborData GetNeighbors(string userId) { + Model.Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Uid == new Guid(userId)); + bool isNull = viking == null || viking.Neighborhood == null; + + Neighbor[] neighbors = { + new Neighbor { + NeighborUserID = isNull ? this.slot0 : viking.Neighborhood.Slot0, + Slot = 0 + }, + new Neighbor { + NeighborUserID = isNull ? this.slot1 : viking.Neighborhood.Slot1, + Slot = 1 + }, + new Neighbor { + NeighborUserID = isNull ? this.slot2 : viking.Neighborhood.Slot2, + Slot = 2 + }, + new Neighbor { + NeighborUserID = isNull ? this.slot3 : viking.Neighborhood.Slot3, + Slot = 3 + }, + new Neighbor { + NeighborUserID = isNull ? this.slot4 : viking.Neighborhood.Slot4, + Slot = 4 + } + }; + + return new NeighborData { + UserID = new Guid(userId), + Neighbors = neighbors + }; + } + } +} diff --git a/src/sodoff.csproj b/src/sodoff.csproj index e1c9bca..cd1b961 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -59,6 +59,7 @@ + @@ -155,6 +156,9 @@ PreserveNewest + + + PreserveNewest