diff --git a/src/Controllers/Common/AchievementController.cs b/src/Controllers/Common/AchievementController.cs
index 0838e4f..a7c3ab3 100644
--- a/src/Controllers/Common/AchievementController.cs
+++ b/src/Controllers/Common/AchievementController.cs
@@ -4,22 +4,42 @@ using Microsoft.AspNetCore.Mvc;
using sodoff.Attributes;
using sodoff.Model;
using sodoff.Schema;
+using sodoff.Services;
using sodoff.Util;
namespace sodoff.Controllers.Common;
public class AchievementController : Controller {
private readonly DBContext ctx;
- public AchievementController(DBContext ctx) {
+ private AchievementService achievementService;
+ public AchievementController(DBContext ctx, AchievementService achievementService) {
this.ctx = ctx;
+ this.achievementService = achievementService;
}
[HttpPost]
- //[Produces("application/xml")]
+ [Produces("application/xml")]
[Route("AchievementWebService.asmx/GetPetAchievementsByUserID")]
- public IActionResult GetPetAchievementsByUserID() {
- // TODO, this is a placeholder
- return Ok("\n");
+ public IActionResult GetPetAchievementsByUserID([FromForm] string apiToken, [FromForm] string userId) {
+ // TODO: check session
+
+ Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Id == userId);
+ if (viking is null) {
+ return null;
+ }
+
+ List dragonsAchievement = new List();
+ foreach (Dragon dragon in viking.Dragons) {
+ dragonsAchievement.Add(
+ achievementService.CreateUserAchievementInfo(dragon.EntityId, dragon.PetXP, AchievementPointTypes.DragonXP)
+ );
+ }
+
+ ArrayOfUserAchievementInfo arrAchievements = new ArrayOfUserAchievementInfo {
+ UserAchievementInfo = dragonsAchievement.ToArray()
+ };
+
+ return Ok(arrAchievements);
}
[HttpPost]
@@ -50,27 +70,19 @@ public class AchievementController : Controller {
[Produces("application/xml")]
[Route("AchievementWebService.asmx/GetAchievementsByUserID")]
public IActionResult GetAchievementsByUserID([FromForm] string userId) {
- // TODO: this is a placeholder
+ // TODO: check session
+
+ Viking? viking = ctx.Vikings.FirstOrDefault(e => e.Id == userId);
+
+ if (viking is null) {
+ return null;
+ }
+
ArrayOfUserAchievementInfo arrAchievements = new ArrayOfUserAchievementInfo {
UserAchievementInfo = new UserAchievementInfo[]{
- new UserAchievementInfo {
- UserID = Guid.Parse(userId),
- AchievementPointTotal = 5000,
- RankID = 30,
- PointTypeID = 1
- },
- new UserAchievementInfo {
- UserID = Guid.Parse(userId),
- AchievementPointTotal = 5000,
- RankID = 30,
- PointTypeID = 9
- },
- new UserAchievementInfo {
- UserID = Guid.Parse(userId),
- AchievementPointTotal = 5000,
- RankID = 30,
- PointTypeID = 10
- },
+ achievementService.CreateUserAchievementInfo(viking, AchievementPointTypes.PlayerXP),
+ achievementService.CreateUserAchievementInfo(viking.Id, 60000, AchievementPointTypes.PlayerFarmingXP), // TODO: placeholder until there is no leveling for farm XP
+ achievementService.CreateUserAchievementInfo(viking.Id, 20000, AchievementPointTypes.PlayerFishingXP), // TODO: placeholder until there is no leveling for fishing XP
}
};
@@ -86,7 +98,7 @@ public class AchievementController : Controller {
return Ok(new AchievementReward[1] {
new AchievementReward {
Amount = 5,
- PointTypeID = 5,
+ PointTypeID = AchievementPointTypes.CashCurrency,
EntityID = Guid.Parse(viking.Id),
EntityTypeID = 1,
RewardID = 552
@@ -94,7 +106,7 @@ public class AchievementController : Controller {
});
}
- [HttpPost]
+ [HttpPost]
[Produces("application/xml")]
[Route("V2/AchievementWebService.asmx/SetUserAchievementTask")]
[DecryptRequest("achievementTaskSetRequest")]
@@ -112,7 +124,7 @@ public class AchievementController : Controller {
AchievementRewards = new AchievementReward[1] {
new AchievementReward {
Amount = 25,
- PointTypeID = 1,
+ PointTypeID = AchievementPointTypes.PlayerXP,
RewardID = 910,
EntityTypeID =1
}
@@ -130,7 +142,7 @@ public class AchievementController : Controller {
return Ok(new AchievementReward[1] {
new AchievementReward {
Amount = 25,
- PointTypeID = 1,
+ PointTypeID = AchievementPointTypes.PlayerXP,
EntityID = Guid.Parse(viking.Id),
EntityTypeID = 1,
RewardID = 552
diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs
index c3f6606..be13269 100644
--- a/src/Controllers/Common/ContentController.cs
+++ b/src/Controllers/Common/ContentController.cs
@@ -428,7 +428,7 @@ public class ContentController : Controller {
return null;
}
- RaisedPetData[] dragons = viking.Dragons
+ RaisedPetData[] dragons = viking.Dragons // TODO (multiplayer) we should use userId
.Where(d => d.RaisedPetData is not null)
.Select(GetRaisedPetDataFromDragon)
.ToArray();
diff --git a/src/Controllers/Common/ProfileController.cs b/src/Controllers/Common/ProfileController.cs
index 4f8df71..761d36f 100644
--- a/src/Controllers/Common/ProfileController.cs
+++ b/src/Controllers/Common/ProfileController.cs
@@ -2,14 +2,17 @@
using Microsoft.AspNetCore.Mvc;
using sodoff.Model;
using sodoff.Schema;
+using sodoff.Services;
using sodoff.Util;
namespace sodoff.Controllers.Common;
public class ProfileController : Controller {
private readonly DBContext ctx;
- public ProfileController(DBContext ctx) {
+ private AchievementService achievementService;
+ public ProfileController(DBContext ctx, AchievementService achievementService) {
this.ctx = ctx;
+ this.achievementService = achievementService;
}
[HttpPost]
@@ -141,24 +144,9 @@ public class ProfileController : Controller {
RankID = 0, // placeholder
AchievementInfo = null, // placeholder
Achievements = new UserAchievementInfo[] {
- new UserAchievementInfo {
- UserID = Guid.Parse(viking.Id),
- AchievementPointTotal = 5000,
- RankID = 30,
- PointTypeID = 1
- },
- new UserAchievementInfo {
- UserID = Guid.Parse(viking.Id),
- AchievementPointTotal = 5000,
- RankID = 30,
- PointTypeID = 9
- },
- new UserAchievementInfo {
- UserID = Guid.Parse(viking.Id),
- AchievementPointTotal = 5000,
- RankID = 30,
- PointTypeID = 10
- },
+ achievementService.CreateUserAchievementInfo(viking, AchievementPointTypes.PlayerXP),
+ achievementService.CreateUserAchievementInfo(viking.Id, 60000, AchievementPointTypes.PlayerFarmingXP), // TODO: placeholder until there is no leveling for farm XP
+ achievementService.CreateUserAchievementInfo(viking.Id, 20000, AchievementPointTypes.PlayerFishingXP), // TODO: placeholder until there is no leveling for fishing XP
}
};
diff --git a/src/Model/AchievementPoints.cs b/src/Model/AchievementPoints.cs
new file mode 100644
index 0000000..9dae51b
--- /dev/null
+++ b/src/Model/AchievementPoints.cs
@@ -0,0 +1,12 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace sodoff.Model;
+public class AchievementPoints {
+ public string VikingId { get; set; }
+
+ public int Type { get; set; }
+
+ public int Value { get; set; }
+
+ public virtual Viking? Viking { get; set; }
+}
diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs
index 6636393..d2ef372 100644
--- a/src/Model/DBContext.cs
+++ b/src/Model/DBContext.cs
@@ -46,6 +46,9 @@ public class DBContext : DbContext {
builder.Entity().HasMany(v => v.Rooms)
.WithOne(e => e.Viking);
+ builder.Entity().HasMany(v => v.AchievementPoints)
+ .WithOne(e => e.Viking);
+
builder.Entity().HasOne(s => s.User)
.WithMany(e => e.Vikings)
.HasForeignKey(e => e.UserId);
@@ -130,5 +133,12 @@ public class DBContext : DbContext {
builder.Entity().HasOne(i => i.Room)
.WithMany(r => r.Items)
.HasForeignKey(e => e.RoomId);
+
+ builder.Entity().HasKey(e => new { e.VikingId, e.Type });
+
+ builder.Entity()
+ .HasOne(e => e.Viking)
+ .WithMany(e => e.AchievementPoints)
+ .HasForeignKey(e => e.VikingId);
}
}
diff --git a/src/Model/Dragon.cs b/src/Model/Dragon.cs
index 1d80e8b..955da55 100644
--- a/src/Model/Dragon.cs
+++ b/src/Model/Dragon.cs
@@ -18,6 +18,8 @@ public class Dragon {
public string? RaisedPetData { get; set; }
+ public int? PetXP { get; set; }
+
public virtual Viking Viking { get; set; } = null!;
public virtual Viking SelectedViking { get; set; } = null!;
}
diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs
index fa3ba14..aed5ce4 100644
--- a/src/Model/Viking.cs
+++ b/src/Model/Viking.cs
@@ -21,6 +21,7 @@ public class Viking {
public virtual ICollection Images { get; set; } = null!;
public virtual ICollection MissionStates { get; set; } = null!;
public virtual ICollection Rooms { get; set; } = null!;
+ public virtual ICollection AchievementPoints { 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 65ea233..41ebc00 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -18,6 +18,7 @@ builder.Services.AddSingleton();
builder.Services.AddScoped();
builder.Services.AddSingleton();
builder.Services.AddScoped();
+builder.Services.AddSingleton();
var app = builder.Build();
diff --git a/src/Schema/AchievementPointTypes.cs b/src/Schema/AchievementPointTypes.cs
new file mode 100644
index 0000000..d1e6c28
--- /dev/null
+++ b/src/Schema/AchievementPointTypes.cs
@@ -0,0 +1,35 @@
+using System.Xml.Serialization;
+
+namespace sodoff.Schema;
+
+public enum AchievementPointTypes {
+ [XmlEnum("1")]
+ PlayerXP = 1,
+
+ [XmlEnum("2")]
+ GameCurrency = 2, // gold
+
+ [XmlEnum("4")]
+ Unknown4 = 4,
+
+ [XmlEnum("5")]
+ CashCurrency = 5, // gems
+
+ [XmlEnum("6")]
+ ItemReward = 6,
+
+ [XmlEnum("8")]
+ DragonXP = 8,
+
+ [XmlEnum("9")]
+ PlayerFarmingXP = 9,
+
+ [XmlEnum("10")]
+ PlayerFishingXP = 10,
+
+ [XmlEnum("12")]
+ UDTPoints = 12,
+
+ [XmlEnum("13")]
+ Unknown13 = 13,
+}
diff --git a/src/Schema/AchievementReward.cs b/src/Schema/AchievementReward.cs
index 9ca16c1..2dc5b5e 100644
--- a/src/Schema/AchievementReward.cs
+++ b/src/Schema/AchievementReward.cs
@@ -13,7 +13,7 @@ public class AchievementReward
public int? Amount;
[XmlElement(ElementName = "p", IsNullable = true)]
- public int? PointTypeID;
+ public AchievementPointTypes? PointTypeID;
[XmlElement(ElementName = "ii")]
public int ItemID;
diff --git a/src/Schema/ArrayOfUserRank.cs b/src/Schema/ArrayOfUserRank.cs
new file mode 100644
index 0000000..e1edb00
--- /dev/null
+++ b/src/Schema/ArrayOfUserRank.cs
@@ -0,0 +1,11 @@
+using System.Diagnostics;
+using System.Xml.Serialization;
+
+namespace sodoff.Schema;
+
+[XmlRoot(ElementName = "ArrayOfUserRank", Namespace = "http://api.jumpstart.com/")]
+[Serializable]
+public class ArrayOfUserRank {
+ [XmlElement(ElementName = "UserRank")]
+ public UserRank[] UserRank;
+}
diff --git a/src/Schema/AvatarData.cs b/src/Schema/AvatarData.cs
index 6b50534..ae55e3e 100644
--- a/src/Schema/AvatarData.cs
+++ b/src/Schema/AvatarData.cs
@@ -7,6 +7,7 @@ namespace sodoff.Schema;
public class AvatarData
{
[XmlElement(ElementName = "IsSuggestedAvatarName", IsNullable = true)]
+ public bool? IsSuggestedAvatarName;
public int? Id;
diff --git a/src/Schema/ItemStateCriteriaReplenishable.cs b/src/Schema/ItemStateCriteriaReplenishable.cs
index f4812fd..51aca38 100644
--- a/src/Schema/ItemStateCriteriaReplenishable.cs
+++ b/src/Schema/ItemStateCriteriaReplenishable.cs
@@ -10,7 +10,7 @@ public class ItemStateCriteriaReplenishable : ItemStateCriteria
public bool ApplyRank;
[XmlElement(ElementName = "PointTypeID", IsNullable = true)]
- public int? PointTypeID;
+ public AchievementPointTypes? PointTypeID;
[XmlElement(ElementName = "ReplenishableRates")]
public List ReplenishableRates;
diff --git a/src/Schema/RewardMultiplier.cs b/src/Schema/RewardMultiplier.cs
index 53a23f9..ecb6a1d 100644
--- a/src/Schema/RewardMultiplier.cs
+++ b/src/Schema/RewardMultiplier.cs
@@ -7,7 +7,7 @@ namespace sodoff.Schema;
public class RewardMultiplier
{
[XmlElement(ElementName = "PT")]
- public int PointTypeID;
+ public AchievementPointTypes PointTypeID;
[XmlElement(ElementName = "MF")]
public int MultiplierFactor;
diff --git a/src/Schema/UserAchievementInfo.cs b/src/Schema/UserAchievementInfo.cs
index d8b2d75..1494e3a 100644
--- a/src/Schema/UserAchievementInfo.cs
+++ b/src/Schema/UserAchievementInfo.cs
@@ -19,7 +19,7 @@ public class UserAchievementInfo
public int RankID;
[XmlElement(ElementName = "p")]
- public int? PointTypeID;
+ public AchievementPointTypes? PointTypeID;
[XmlElement(ElementName = "FBUID", IsNullable = true)]
public long? FacebookUserID;
diff --git a/src/Schema/UserRank.cs b/src/Schema/UserRank.cs
new file mode 100644
index 0000000..9063dd8
--- /dev/null
+++ b/src/Schema/UserRank.cs
@@ -0,0 +1,20 @@
+using System.Diagnostics;
+using System.Xml.Serialization;
+
+namespace sodoff.Schema;
+
+[XmlRoot(ElementName = "UserRank", Namespace = "")]
+[Serializable]
+public class UserRank {
+ [XmlElement(ElementName = "PointTypeID")]
+ public AchievementPointTypes PointTypeID;
+
+ [XmlElement(ElementName = "Value")]
+ public int Value;
+
+ [XmlElement(ElementName = "RankID")]
+ public int? RankID;
+
+ [XmlElement(ElementName = "GlobalRankID")]
+ public int? GlobalRankID;
+}
diff --git a/src/Services/AchievementService.cs b/src/Services/AchievementService.cs
new file mode 100644
index 0000000..a6ea48b
--- /dev/null
+++ b/src/Services/AchievementService.cs
@@ -0,0 +1,56 @@
+using sodoff.Schema;
+using sodoff.Model;
+using sodoff.Util;
+using System.Reflection;
+using System.Xml;
+using System.Xml.Linq;
+
+namespace sodoff.Services {
+ public class AchievementService {
+
+ Dictionary ranks = new();
+
+ public AchievementService() {
+ ArrayOfUserRank allranks = XmlUtil.DeserializeXml(XmlUtil.ReadResourceXmlString("allranks"));
+
+ foreach (var pointType in Enum.GetValues()) {
+ ranks[pointType] = allranks.UserRank.Where(r => r.PointTypeID == pointType).ToArray();
+ }
+ }
+
+ public int GetRankFromXP(int? xpPoints, AchievementPointTypes type) {
+ return ranks[type].Count(r => r.Value <= xpPoints);
+ }
+
+ public UserAchievementInfo CreateUserAchievementInfo(string userId, int? value, AchievementPointTypes type) {
+ if (value is null)
+ value = 0;
+ return new UserAchievementInfo {
+ UserID = Guid.Parse(userId),
+ AchievementPointTotal = value,
+ RankID = GetRankFromXP(value, type),
+ PointTypeID = type
+ };
+ }
+
+ public UserAchievementInfo CreateUserAchievementInfo(Viking viking, AchievementPointTypes type) {
+ return CreateUserAchievementInfo(viking.Id, viking.AchievementPoints.FirstOrDefault(a => a.Type == (int)type)?.Value, type);
+ }
+
+ public void AddAchievementPoints(Viking viking, AchievementPointTypes? type, int? value) {
+ if (type == AchievementPointTypes.DragonXP) {
+ viking.SelectedDragon.PetXP = (viking.SelectedDragon.PetXP ?? 0) + (value ?? 0);
+ } else if (type != null) {
+ AchievementPoints xpPoints = viking.AchievementPoints.FirstOrDefault(a => a.Type == (int)type);
+ if (xpPoints is null) {
+ xpPoints = new AchievementPoints {
+ Type = (int)type,
+ Value = 0
+ };
+ viking.AchievementPoints.Add(xpPoints);
+ }
+ xpPoints.Value += value ?? 0;
+ }
+ }
+ }
+}
diff --git a/src/Services/MissionService.cs b/src/Services/MissionService.cs
index 79f7fcc..8ad337c 100644
--- a/src/Services/MissionService.cs
+++ b/src/Services/MissionService.cs
@@ -8,8 +8,9 @@ public class MissionService {
private readonly DBContext ctx;
private MissionStoreSingleton missionStore;
+ private AchievementService achievementService;
- public MissionService(DBContext ctx, MissionStoreSingleton missionStore) {
+ public MissionService(DBContext ctx, MissionStoreSingleton missionStore, AchievementService achievementService) {
this.ctx = ctx;
this.missionStore = missionStore;
}
@@ -49,7 +50,7 @@ public class MissionService {
missionState.UserAccepted = null;
}
foreach (var reward in mission.Rewards) {
- if (reward.PointTypeID == 6) {
+ if (reward.PointTypeID == AchievementPointTypes.ItemReward) {
// TODO: This is not a pretty solution. Use inventory service in the future
InventoryItem? ii = viking.Inventory.InventoryItems.FirstOrDefault(x => x.ItemId == reward.ItemID);
if (ii is null) {
@@ -60,6 +61,8 @@ public class MissionService {
viking.Inventory.InventoryItems.Add(ii);
}
ii.Quantity += (int)reward.Amount!;
+ } else { // currencies, all types of player XP and dragon XP
+ achievementService.AddAchievementPoints(viking, reward.PointTypeID, reward.Amount);
}
}
ctx.SaveChanges();
diff --git a/src/Services/RoomService.cs b/src/Services/RoomService.cs
index cc1df72..291d7e5 100644
--- a/src/Services/RoomService.cs
+++ b/src/Services/RoomService.cs
@@ -125,7 +125,7 @@ public class RoomService {
if (rewards != null) {
response.Rewards = rewards;
foreach (var reward in rewards) {
- if (reward.PointTypeID == 6) {
+ if (reward.PointTypeID == AchievementPointTypes.ItemReward) {
// TODO: This is not a pretty solution. Use inventory service in the future
InventoryItem? ii = item.Room.Viking.Inventory.InventoryItems.FirstOrDefault(x => x.ItemId == reward.ItemID);
if (ii is null) {