From 3877a8ba376065e31c633ebabcccd699bb88cc03 Mon Sep 17 00:00:00 2001 From: ABrokenTV <110191923+ABrokenTV@users.noreply.github.com> Date: Mon, 23 Jun 2025 03:51:11 -0500 Subject: [PATCH 01/18] Fix spawn for Skulder in "Boneknapper, Kidnapped? [2020]" (#23) --- src/Resources/missions/missions_sod.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/missions/missions_sod.xml b/src/Resources/missions/missions_sod.xml index c9f1525..28a10dc 100644 --- a/src/Resources/missions/missions_sod.xml +++ b/src/Resources/missions/missions_sod.xml @@ -49061,7 +49061,7 @@ 2897 Dreadfall2020Q01 10 - <Data><Repeat>0</Repeat><Hidden>0</Hidden><Reward><Asset>PfUiMissionRewardDBDO</Asset></Reward><Random>0</Random><Title><Text>Boneknapper, Kidnapped? [2020]</Text></Title><Icon>RS_DATA/SquadTacticsDreadfallDO.unity3d/IcoDWDragonsHUDDazeReward</Icon></Data> + <Data><Repeat>0</Repeat><Hidden>0</Hidden><Reward><Asset>PfUiMissionRewardDBDO</Asset></Reward><Random>0</Random><Title><Text>Boneknapper, Kidnapped? [2020]</Text></Title><Icon>RS_DATA/SquadTacticsDreadfallDO.unity3d/IcoDWDragonsHUDDazeReward</Icon><Setup><Scene>HubDragonsEdgeDO</Scene><Asset>RS_DATA/PfDWArchaeologist.unity3d/PfDWArchaeologist</Asset><Location>PfMarker_Archaeologist</Location><Recursive>false</Recursive><Persistent>false</Persistent></Setup></Data> false 0 From 640d7ba664c17ad73db2ca8391fe8cf13e486e6c Mon Sep 17 00:00:00 2001 From: Spirtix Date: Thu, 26 Jun 2025 17:43:59 +0200 Subject: [PATCH 02/18] switch to .net 9 --- src/sodoff.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sodoff.csproj b/src/sodoff.csproj index b8fe201..83633a9 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -1,7 +1,7 @@  - net6.0 + net9.0 enable enable true From 3ffced2b60b20849a0a289d684a085257147d3f8 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Thu, 26 Jun 2025 18:06:29 +0200 Subject: [PATCH 03/18] password rehashing asp net identity v3 uses a new hashing algorithm (hmac-sha256) --- src/Controllers/Common/AuthenticationController.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Controllers/Common/AuthenticationController.cs b/src/Controllers/Common/AuthenticationController.cs index 3fc5548..465680a 100644 --- a/src/Controllers/Common/AuthenticationController.cs +++ b/src/Controllers/Common/AuthenticationController.cs @@ -48,11 +48,15 @@ public class AuthenticationController : Controller { } else { user = ctx.Users.FirstOrDefault(e => e.Username == data.UserName); } - - if (user is null || new PasswordHasher().VerifyHashedPassword(null, user.Password, data.Password) != PasswordVerificationResult.Success) { + PasswordVerificationResult result = new PasswordHasher().VerifyHashedPassword(null, user.Password, data.Password); + if (user is null || result == PasswordVerificationResult.Failed) { return Ok(new ParentLoginInfo { Status = MembershipUserStatus.InvalidPassword }); } + if (result == PasswordVerificationResult.SuccessRehashNeeded) { + user.Password = new PasswordHasher().HashPassword(null, data.Password); + } + // Create session Session session = new Session { User = user, From dc303d871e8d66b1e67e4e45a4a55ad057e433c2 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Thu, 26 Jun 2025 21:41:50 +0200 Subject: [PATCH 04/18] mission deep copy .net 8 deprecated BinaryFormatter serialization apart from that proper deep copies are ~10x faster --- src/Schema/AchievementReward.cs | 25 ++++++++++++-- src/Schema/BluePrint.cs | 13 ++++++-- src/Schema/BluePrintDeductibleConfig.cs | 14 ++++++-- src/Schema/BluePrintSpecification.cs | 18 +++++++++-- src/Schema/CompletionAction.cs | 11 +++++-- src/Schema/ItemAttribute.cs | 12 +++++-- src/Schema/ItemAvailability.cs | 12 +++++-- src/Schema/ItemData.cs | 43 +++++++++++++++++++++++-- src/Schema/ItemDataCategory.cs | 13 ++++++-- src/Schema/ItemDataRelationship.cs | 15 +++++++-- src/Schema/ItemDataRollover.cs | 12 +++++-- src/Schema/ItemDataTexture.cs | 14 ++++++-- src/Schema/ItemPossibleStatsMap.cs | 14 ++++++-- src/Schema/ItemSaleConfig.cs | 15 +++++++-- src/Schema/ItemStat.cs | 14 ++++++-- src/Schema/ItemState.cs | 16 +++++++-- src/Schema/ItemStateCriteria.cs | 11 +++++-- src/Schema/ItemStateRule.cs | 12 +++++-- src/Schema/ItemStatsMap.cs | 13 ++++++-- src/Schema/Mission.cs | 24 ++++++++++++++ src/Schema/MissionCriteria.cs | 10 ++++++ src/Schema/MissionRule.cs | 7 ++++ src/Schema/Pair.cs | 13 ++++++-- src/Schema/PairData.cs | 6 ++++ src/Schema/PrerequisiteItem.cs | 9 ++++++ src/Schema/RuleItem.cs | 9 ++++++ src/Schema/Stat.cs | 15 +++++++-- src/Schema/StatRangeMap.cs | 15 +++++++-- src/Schema/Task.cs | 11 +++++++ src/Schema/UserItemData.cs | 20 ++++++++++-- src/Services/MissionStoreSingleton.cs | 14 +------- src/sodoff.csproj | 1 - 32 files changed, 368 insertions(+), 83 deletions(-) diff --git a/src/Schema/AchievementReward.cs b/src/Schema/AchievementReward.cs index 821e5c3..20f0a26 100644 --- a/src/Schema/AchievementReward.cs +++ b/src/Schema/AchievementReward.cs @@ -4,9 +4,28 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "AR", Namespace = "")] [Serializable] -public class AchievementReward -{ - [XmlElement(ElementName = "ui", IsNullable = true)] +public class AchievementReward { + public AchievementReward() {} + + public AchievementReward(AchievementReward other) { + if (other.UserItem != null) + UserItem = new UserItemData(other.UserItem); + + Amount = other.Amount; + PointTypeID = other.PointTypeID; + ItemID = other.ItemID; + EntityID = other.EntityID; + EntityTypeID = other.EntityTypeID; + RewardID = other.RewardID; + AchievementID = other.AchievementID; + AllowMultiple = other.AllowMultiple; + MinAmount = other.MinAmount; + MaxAmount = other.MaxAmount; + Date = other.Date; + CommonInventoryID = other.CommonInventoryID; + } + + [XmlElement(ElementName = "ui", IsNullable = true)] public UserItemData UserItem { get; set; } [XmlElement(ElementName = "a")] diff --git a/src/Schema/BluePrint.cs b/src/Schema/BluePrint.cs index 3c5aeda..e7f81b8 100644 --- a/src/Schema/BluePrint.cs +++ b/src/Schema/BluePrint.cs @@ -5,9 +5,16 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "BP", Namespace = "", IsNullable = true)] [Serializable] -public class BluePrint -{ - [XmlElement(ElementName = "BPDC", IsNullable = true)] +public class BluePrint { + public BluePrint() {} + + public BluePrint(BluePrint other) { + Deductibles = other.Deductibles.Select(d => new BluePrintDeductibleConfig(d)).ToList(); + Ingredients = other.Ingredients.Select(i => new BluePrintSpecification(i)).ToList(); + Outputs = other.Outputs.Select(o => new BluePrintSpecification(o)).ToList(); + } + + [XmlElement(ElementName = "BPDC", IsNullable = true)] public List Deductibles { get; set; } [XmlElement(ElementName = "ING", IsNullable = false)] diff --git a/src/Schema/BluePrintDeductibleConfig.cs b/src/Schema/BluePrintDeductibleConfig.cs index e42025d..a83012c 100644 --- a/src/Schema/BluePrintDeductibleConfig.cs +++ b/src/Schema/BluePrintDeductibleConfig.cs @@ -4,9 +4,17 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "BPDC", Namespace = "", IsNullable = true)] [Serializable] -public class BluePrintDeductibleConfig -{ - [XmlElement(ElementName = "BPIID", IsNullable = false)] +public class BluePrintDeductibleConfig { + public BluePrintDeductibleConfig() {} + + public BluePrintDeductibleConfig(BluePrintDeductibleConfig other) { + BluePrintItemID = other.BluePrintItemID; + DeductibleType = other.DeductibleType; + ItemID = other.ItemID; + Quantity = other.Quantity; + } + + [XmlElement(ElementName = "BPIID", IsNullable = false)] public int BluePrintItemID { get; set; } [XmlElement(ElementName = "DT", IsNullable = false)] diff --git a/src/Schema/BluePrintSpecification.cs b/src/Schema/BluePrintSpecification.cs index 6f235b7..2851c8c 100644 --- a/src/Schema/BluePrintSpecification.cs +++ b/src/Schema/BluePrintSpecification.cs @@ -2,9 +2,21 @@ using System.Xml.Serialization; namespace sodoff.Schema; -public class BluePrintSpecification -{ - [XmlElement(ElementName = "BPSID", IsNullable = false)] +public class BluePrintSpecification { + public BluePrintSpecification() {} + + public BluePrintSpecification(BluePrintSpecification other) { + BluePrintSpecID = other.BluePrintSpecID; + BluePrintItemID = other.BluePrintItemID; + ItemID = other.ItemID; + CategoryID = other.CategoryID; + ItemRarity = other.ItemRarity; + Tier = other.Tier; + Quantity = other.Quantity; + SpecificationType = other.SpecificationType; + } + + [XmlElement(ElementName = "BPSID", IsNullable = false)] public int BluePrintSpecID { get; set; } [XmlElement(ElementName = "BPIID", IsNullable = false)] diff --git a/src/Schema/CompletionAction.cs b/src/Schema/CompletionAction.cs index b318f64..8e9e9e2 100644 --- a/src/Schema/CompletionAction.cs +++ b/src/Schema/CompletionAction.cs @@ -3,8 +3,13 @@ using System.Xml.Serialization; namespace sodoff.Schema; [Serializable] -public class CompletionAction -{ - [XmlElement(ElementName = "Transition")] +public class CompletionAction { + public CompletionAction() {} + + public CompletionAction(CompletionAction other) { + Transition = other.Transition; + } + + [XmlElement(ElementName = "Transition")] public StateTransition Transition; } diff --git a/src/Schema/ItemAttribute.cs b/src/Schema/ItemAttribute.cs index e62801a..a5c3056 100644 --- a/src/Schema/ItemAttribute.cs +++ b/src/Schema/ItemAttribute.cs @@ -4,9 +4,15 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "AT", Namespace = "")] [Serializable] -public class ItemAttribute -{ - [XmlElement(ElementName = "k")] +public class ItemAttribute { + public ItemAttribute() {} + + public ItemAttribute(ItemAttribute other) { + Key = other.Key; + Value = other.Value; + } + + [XmlElement(ElementName = "k")] public string Key; [XmlElement(ElementName = "v")] diff --git a/src/Schema/ItemAvailability.cs b/src/Schema/ItemAvailability.cs index 9b10bab..898a666 100644 --- a/src/Schema/ItemAvailability.cs +++ b/src/Schema/ItemAvailability.cs @@ -4,9 +4,15 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Availability", Namespace = "")] [Serializable] -public class ItemAvailability -{ - [XmlElement(ElementName = "sdate", IsNullable = true)] +public class ItemAvailability { + public ItemAvailability() {} + + public ItemAvailability(ItemAvailability other) { + StartDate = other.StartDate; + EndDate = other.EndDate; + } + + [XmlElement(ElementName = "sdate", IsNullable = true)] public DateTime? StartDate; [XmlElement(ElementName = "edate", IsNullable = true)] diff --git a/src/Schema/ItemData.cs b/src/Schema/ItemData.cs index fc18947..c8b591a 100644 --- a/src/Schema/ItemData.cs +++ b/src/Schema/ItemData.cs @@ -3,9 +3,46 @@ using System.Xml.Serialization; namespace sodoff.Schema; [XmlRoot(ElementName = "I", Namespace = "", IsNullable = true)] -public class ItemData -{ - [XmlElement(ElementName = "is")] +public class ItemData { + public ItemData() {} + + public ItemData(ItemData other) { + ItemStates = other.ItemStates.Select(s => new ItemState(s)).ToList(); + ItemRarity = other.ItemRarity; + PossibleStatsMap = new ItemPossibleStatsMap(other.PossibleStatsMap); + ItemStatsMap = new ItemStatsMap(other.ItemStatsMap); + ItemSaleConfigs = other.ItemSaleConfigs.Select(cfg => new ItemSaleConfig(cfg)).ToArray(); + BluePrint = new BluePrint(other.BluePrint); + AssetName = other.AssetName; + Attribute = other.Attribute.Select(attr => new ItemAttribute(attr)).ToArray(); + Category = other.Category.Select(cat => new ItemDataCategory(cat)).ToArray(); + Cost = other.Cost; + CashCost = other.CashCost; + CreativePoints = other.CreativePoints; + Description = other.Description; + IconName = other.IconName; + InventoryMax = other.InventoryMax; + ItemID = other.ItemID; + ItemName = other.ItemName; + ItemNamePlural = other.ItemNamePlural; + Locked = other.Locked; + Geometry2 = other.Geometry2; + Rollover = new ItemDataRollover(other.Rollover); + RankId = other.RankId; + Relationship = other.Relationship.Select(r => new ItemDataRelationship(r)).ToArray(); + Stackable = other.Stackable; + AllowStacking = other.AllowStacking; + SaleFactor = other.SaleFactor; + Texture = other.Texture.Select(t => new ItemDataTexture(t)).ToArray(); + Uses = other.Uses; + Availability = other.Availability.Select(a => new ItemAvailability(a)).ToArray(); + RewardTypeID = other.RewardTypeID; + Points = other.Points; + NormalDiscoutModifier = other.NormalDiscoutModifier; + MemberDiscountModifier = other.MemberDiscountModifier; + } + + [XmlElement(ElementName = "is")] public List ItemStates { get; set; } [XmlElement(ElementName = "ir", IsNullable = true)] diff --git a/src/Schema/ItemDataCategory.cs b/src/Schema/ItemDataCategory.cs index de91e1d..6e5cb55 100644 --- a/src/Schema/ItemDataCategory.cs +++ b/src/Schema/ItemDataCategory.cs @@ -4,9 +4,16 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IC", Namespace = "")] [Serializable] -public class ItemDataCategory -{ - [XmlElement(ElementName = "cid")] +public class ItemDataCategory { + public ItemDataCategory() {} + + public ItemDataCategory(ItemDataCategory other) { + CategoryId = other.CategoryId; + CategoryName = other.CategoryName; + IconName = other.IconName; + } + + [XmlElement(ElementName = "cid")] public int CategoryId; [XmlElement(ElementName = "cn")] diff --git a/src/Schema/ItemDataRelationship.cs b/src/Schema/ItemDataRelationship.cs index c15424b..f340ecf 100644 --- a/src/Schema/ItemDataRelationship.cs +++ b/src/Schema/ItemDataRelationship.cs @@ -4,9 +4,18 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IRE", Namespace = "")] [Serializable] -public class ItemDataRelationship -{ - [XmlElement(ElementName = "t")] +public class ItemDataRelationship { + public ItemDataRelationship() {} + + public ItemDataRelationship(ItemDataRelationship other) { + Type = other.Type; + ItemId = other.ItemId; + Weight = other.Weight; + Quantity = other.Quantity; + MaxQuantity = other.MaxQuantity; + } + + [XmlElement(ElementName = "t")] public string Type; [XmlElement(ElementName = "id")] diff --git a/src/Schema/ItemDataRollover.cs b/src/Schema/ItemDataRollover.cs index e4b1e33..baee86f 100644 --- a/src/Schema/ItemDataRollover.cs +++ b/src/Schema/ItemDataRollover.cs @@ -4,9 +4,15 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IRO", Namespace = "")] [Serializable] -public class ItemDataRollover -{ - [XmlElement(ElementName = "d")] +public class ItemDataRollover { + public ItemDataRollover() {} + + public ItemDataRollover(ItemDataRollover other) { + DialogName = other.DialogName; + Bundle = other.Bundle; + } + + [XmlElement(ElementName = "d")] public string DialogName; [XmlElement(ElementName = "b")] diff --git a/src/Schema/ItemDataTexture.cs b/src/Schema/ItemDataTexture.cs index 35e155e..1650352 100644 --- a/src/Schema/ItemDataTexture.cs +++ b/src/Schema/ItemDataTexture.cs @@ -4,9 +4,17 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IT", Namespace = "")] [Serializable] -public class ItemDataTexture -{ - [XmlElement(ElementName = "n")] +public class ItemDataTexture { + public ItemDataTexture() {} + + public ItemDataTexture(ItemDataTexture other) { + TextureName = other.TextureName; + TextureTypeName = other.TextureTypeName; + OffsetX = other.OffsetX; + OffsetY = other.OffsetY; + } + + [XmlElement(ElementName = "n")] public string TextureName; [XmlElement(ElementName = "t")] diff --git a/src/Schema/ItemPossibleStatsMap.cs b/src/Schema/ItemPossibleStatsMap.cs index 6087d5a..ac577b0 100644 --- a/src/Schema/ItemPossibleStatsMap.cs +++ b/src/Schema/ItemPossibleStatsMap.cs @@ -4,9 +4,17 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IPSM", Namespace = "", IsNullable = false)] [Serializable] -public class ItemPossibleStatsMap -{ - [XmlElement(ElementName = "IID", IsNullable = false)] +public class ItemPossibleStatsMap { + public ItemPossibleStatsMap() {} + + public ItemPossibleStatsMap(ItemPossibleStatsMap other) { + ItemID = other.ItemID; + ItemStatsCount = other.ItemStatsCount; + SetID = other.SetID; + Stats = other.Stats.Select(s => new Stat(s)).ToList(); + } + + [XmlElement(ElementName = "IID", IsNullable = false)] public int ItemID { get; set; } [XmlElement(ElementName = "SC", IsNullable = false)] diff --git a/src/Schema/ItemSaleConfig.cs b/src/Schema/ItemSaleConfig.cs index 0495ed7..0528167 100644 --- a/src/Schema/ItemSaleConfig.cs +++ b/src/Schema/ItemSaleConfig.cs @@ -4,9 +4,18 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ISC", Namespace = "", IsNullable = true)] [Serializable] -public class ItemSaleConfig -{ - [XmlElement(ElementName = "IID", IsNullable = true)] +public class ItemSaleConfig { + public ItemSaleConfig() {} + + public ItemSaleConfig(ItemSaleConfig other) { + ItemID = other.ItemID; + CategoryID = other.CategoryID; + RarityID = other.RarityID; + Quantity = other.Quantity; + RewardItemID = other.RewardItemID; + } + + [XmlElement(ElementName = "IID", IsNullable = true)] public int? ItemID { get; set; } [XmlElement(ElementName = "CID", IsNullable = true)] diff --git a/src/Schema/ItemStat.cs b/src/Schema/ItemStat.cs index e7431e2..3a1b9c0 100644 --- a/src/Schema/ItemStat.cs +++ b/src/Schema/ItemStat.cs @@ -4,9 +4,17 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IS", Namespace = "")] [Serializable] -public class ItemStat -{ - [XmlElement(ElementName = "ID")] +public class ItemStat { + public ItemStat() {} + + public ItemStat(ItemStat other) { + ItemStatID = other.ItemStatID; + Name = other.Name; + Value = other.Value; + DataType = other.DataType; + } + + [XmlElement(ElementName = "ID")] public int ItemStatID { get; set; } [XmlElement(ElementName = "N")] diff --git a/src/Schema/ItemState.cs b/src/Schema/ItemState.cs index a8d1351..a39af77 100644 --- a/src/Schema/ItemState.cs +++ b/src/Schema/ItemState.cs @@ -4,9 +4,19 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ItemState", Namespace = "")] [Serializable] -public class ItemState -{ - [XmlElement(ElementName = "ItemStateID")] +public class ItemState { + public ItemState() { } + + public ItemState(ItemState other) { + ItemStateID = other.ItemStateID; + Name = other.Name; + Rule = new ItemStateRule(other.Rule); + Order = other.Order; + AchievementID = other.AchievementID; + Rewards = other.Rewards.Select(r => new AchievementReward(r)).ToArray(); + } + + [XmlElement(ElementName = "ItemStateID")] public int ItemStateID; [XmlElement(ElementName = "Name")] diff --git a/src/Schema/ItemStateCriteria.cs b/src/Schema/ItemStateCriteria.cs index 9510796..715946f 100644 --- a/src/Schema/ItemStateCriteria.cs +++ b/src/Schema/ItemStateCriteria.cs @@ -10,8 +10,13 @@ namespace sodoff.Schema; [XmlInclude(typeof(ItemStateCriteriaSpeedUpItem))] [XmlInclude(typeof(ItemStateCriteriaExpiry))] [Serializable] -public class ItemStateCriteria -{ - [XmlElement(ElementName = "Type")] +public class ItemStateCriteria { + public ItemStateCriteria() {} + + public ItemStateCriteria(ItemStateCriteria other) { + Type = other.Type; + } + + [XmlElement(ElementName = "Type")] public ItemStateCriteriaType Type; } diff --git a/src/Schema/ItemStateRule.cs b/src/Schema/ItemStateRule.cs index 2685c40..162efb4 100644 --- a/src/Schema/ItemStateRule.cs +++ b/src/Schema/ItemStateRule.cs @@ -4,9 +4,15 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ItemStateRule", Namespace = "")] [Serializable] -public class ItemStateRule -{ - [XmlElement(ElementName = "Criterias")] +public class ItemStateRule { + public ItemStateRule() {} + + public ItemStateRule(ItemStateRule other) { + Criterias = other.Criterias.Select(c => new ItemStateCriteria(c)).ToList(); + CompletionAction = new CompletionAction(other.CompletionAction); + } + + [XmlElement(ElementName = "Criterias")] public List Criterias; [XmlElement(ElementName = "CompletionAction")] diff --git a/src/Schema/ItemStatsMap.cs b/src/Schema/ItemStatsMap.cs index 0c090bc..280500a 100644 --- a/src/Schema/ItemStatsMap.cs +++ b/src/Schema/ItemStatsMap.cs @@ -4,9 +4,16 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ISM", Namespace = "", IsNullable = false)] [Serializable] -public class ItemStatsMap -{ - [XmlElement(ElementName = "IID", IsNullable = false)] +public class ItemStatsMap { + public ItemStatsMap() {} + + public ItemStatsMap(ItemStatsMap other) { + ItemID = other.ItemID; + ItemTier = other.ItemTier; + ItemStats = other.ItemStats.Select(s => new ItemStat(s)).ToArray(); + } + + [XmlElement(ElementName = "IID", IsNullable = false)] public int ItemID { get; set; } [XmlElement(ElementName = "IT", IsNullable = false)] diff --git a/src/Schema/Mission.cs b/src/Schema/Mission.cs index 43ecb21..1e49c29 100644 --- a/src/Schema/Mission.cs +++ b/src/Schema/Mission.cs @@ -5,6 +5,30 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Mission", Namespace = "")] [Serializable] // FIXME: Remove serializable once we have a different way of deep copying than BinaryFormatter public class Mission { + public Mission() {} + + public Mission(Mission other) { + if (other == null) throw new ArgumentNullException(nameof(other)); + MissionID = other.MissionID; + Name = other.Name; + GroupID = other.GroupID; + ParentID = other.ParentID; + Static = other.Static; + Accepted = other.Accepted; + Completed = other.Completed; + Rule = other.Rule; + VersionID = other.VersionID; + AchievementID = other.AchievementID; + AcceptanceAchievementID = other.AcceptanceAchievementID; + Repeatable = other.Repeatable; + MissionRule = new MissionRule(other.MissionRule); + + Missions = other.Missions.Select(m => new Mission(m)).ToList(); + Tasks = other.Tasks.Select(t => new Task(t)).ToList(); + Rewards = other.Rewards.Select(r => new AchievementReward(r)).ToList(); + AcceptanceRewards = other.AcceptanceRewards.Select(a => new AchievementReward(a)).ToList(); + } + [XmlElement(ElementName = "I")] public int MissionID; diff --git a/src/Schema/MissionCriteria.cs b/src/Schema/MissionCriteria.cs index 5ff9d2d..29c867f 100644 --- a/src/Schema/MissionCriteria.cs +++ b/src/Schema/MissionCriteria.cs @@ -5,6 +5,16 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "MissionCriteria", Namespace = "")] [Serializable] public class MissionCriteria { + public MissionCriteria() {} + + public MissionCriteria(MissionCriteria other) { + Type = other.Type; + Ordered = other.Ordered; + Min = other.Min; + Repeat = other.Repeat; + RuleItems = other.RuleItems.Select(r => new RuleItem(r)).ToList(); + } + [XmlElement(ElementName = "Type")] public string Type; diff --git a/src/Schema/MissionRule.cs b/src/Schema/MissionRule.cs index 2a1877f..3a9e6a5 100644 --- a/src/Schema/MissionRule.cs +++ b/src/Schema/MissionRule.cs @@ -5,6 +5,13 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "MissionRule", Namespace = "")] [Serializable] public class MissionRule { + public MissionRule() {} + + public MissionRule(MissionRule other) { + Prerequisites = other.Prerequisites.Select(p => new PrerequisiteItem(p)).ToList(); + Criteria = new MissionCriteria(other.Criteria); + } + [XmlElement(ElementName = "Prerequisites")] public List Prerequisites; diff --git a/src/Schema/Pair.cs b/src/Schema/Pair.cs index c14b803..485d3d8 100644 --- a/src/Schema/Pair.cs +++ b/src/Schema/Pair.cs @@ -4,9 +4,16 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Pair", Namespace = "")] [Serializable] -public class Pair -{ - [XmlElement(ElementName = "PairKey")] +public class Pair { + public Pair() {} + + public Pair(Pair other) { + PairKey = other.PairKey; + PairValue = other.PairValue; + UpdateDate = other.UpdateDate; + } + + [XmlElement(ElementName = "PairKey")] public string PairKey; [XmlElement(ElementName = "PairValue")] diff --git a/src/Schema/PairData.cs b/src/Schema/PairData.cs index ffb862f..46438ff 100644 --- a/src/Schema/PairData.cs +++ b/src/Schema/PairData.cs @@ -5,6 +5,12 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Pairs", Namespace = "", IsNullable = true)] [Serializable] public class PairData { + public PairData() {} + + public PairData(PairData other) { + Pairs = other.Pairs.Select(p => new Pair(p)).ToArray(); + } + [XmlElement("Pair", IsNullable = true)] public Pair[] Pairs { get; set; } } \ No newline at end of file diff --git a/src/Schema/PrerequisiteItem.cs b/src/Schema/PrerequisiteItem.cs index 69cb33d..8d555a4 100644 --- a/src/Schema/PrerequisiteItem.cs +++ b/src/Schema/PrerequisiteItem.cs @@ -5,6 +5,15 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "PrerequisiteItem", Namespace = "")] [Serializable] public class PrerequisiteItem { + public PrerequisiteItem() {} + + public PrerequisiteItem(PrerequisiteItem other) { + Type = other.Type; + Value = other.Value; + Quantity = other.Quantity; + ClientRule = other.ClientRule; + } + [XmlElement(ElementName = "Type")] public PrerequisiteRequiredType Type; diff --git a/src/Schema/RuleItem.cs b/src/Schema/RuleItem.cs index 5c106d9..3478454 100644 --- a/src/Schema/RuleItem.cs +++ b/src/Schema/RuleItem.cs @@ -5,6 +5,15 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "RuleItem", Namespace = "")] [Serializable] public class RuleItem { + public RuleItem() {} + + public RuleItem(RuleItem other) { + Type = other.Type; + MissionID = other.MissionID; + ID = other.ID; + Complete = other.Complete; + } + [XmlElement(ElementName = "Type")] public RuleItemType Type; diff --git a/src/Schema/Stat.cs b/src/Schema/Stat.cs index f85fd4b..ea9fc3a 100644 --- a/src/Schema/Stat.cs +++ b/src/Schema/Stat.cs @@ -4,9 +4,18 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "STAT", Namespace = "", IsNullable = false)] [Serializable] -public class Stat -{ - [XmlElement(ElementName = "IID", IsNullable = false)] +public class Stat { + public Stat() {} + + public Stat(Stat other) { + ItemID = other.ItemID; + ItemStatsID = other.ItemStatsID; + SetID = other.SetID; + Probability = other.Probability; + ItemStatsRangeMaps = other.ItemStatsRangeMaps.Select(s => new StatRangeMap(s)).ToList(); + } + + [XmlElement(ElementName = "IID", IsNullable = false)] public int ItemID { get; set; } [XmlElement(ElementName = "ISID", IsNullable = false)] diff --git a/src/Schema/StatRangeMap.cs b/src/Schema/StatRangeMap.cs index 7c74a6b..6b8c7c5 100644 --- a/src/Schema/StatRangeMap.cs +++ b/src/Schema/StatRangeMap.cs @@ -4,9 +4,18 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "SRM", Namespace = "", IsNullable = false)] [Serializable] -public class StatRangeMap -{ - [XmlElement(ElementName = "ISID", IsNullable = false)] +public class StatRangeMap { + public StatRangeMap() {} + + public StatRangeMap(StatRangeMap other) { + ItemStatsID = other.ItemStatsID; + ItemStatsName = other.ItemStatsName; + ItemTierID = other.ItemTierID; + StartRange = other.StartRange; + EndRange = other.EndRange; + } + + [XmlElement(ElementName = "ISID", IsNullable = false)] public int ItemStatsID { get; set; } [XmlElement(ElementName = "ISN", IsNullable = false)] diff --git a/src/Schema/Task.cs b/src/Schema/Task.cs index 1f66a0b..f0f19b6 100644 --- a/src/Schema/Task.cs +++ b/src/Schema/Task.cs @@ -8,6 +8,17 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Task", Namespace = "")] [Serializable] public class Task { + public Task() {} + + public Task(Task other) { + TaskID = other.TaskID; + Name = other.Name; + Static = other.Static; + Completed = other.Completed; + Failed = other.Failed; + Payload = other.Payload; + } + [XmlElement(ElementName = "I")] public int TaskID; diff --git a/src/Schema/UserItemData.cs b/src/Schema/UserItemData.cs index 4c908e7..1e52f1c 100644 --- a/src/Schema/UserItemData.cs +++ b/src/Schema/UserItemData.cs @@ -4,9 +4,23 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "UserItem", Namespace = "")] [Serializable] -public class UserItemData -{ - [XmlElement(ElementName = "iid")] +public class UserItemData { + public UserItemData() {} + + public UserItemData(UserItemData other) { + ItemID = other.ItemID; + ModifiedDate = other.ModifiedDate; + UserItemAttributes = new PairData(other.UserItemAttributes); + ItemStats = other.ItemStats.Select(stat => new ItemStat(stat)).ToArray(); + ItemTier = other.ItemTier; + CreatedDate = other.CreatedDate; + UserInventoryID = other.UserInventoryID; + Quantity = other.Quantity; + Uses = other.Uses; + Item = new ItemData(other.Item); + } + + [XmlElement(ElementName = "iid")] public int ItemID { get; set; } [XmlElement(ElementName = "md", IsNullable = true)] diff --git a/src/Services/MissionStoreSingleton.cs b/src/Services/MissionStoreSingleton.cs index 09da06f..f25532e 100644 --- a/src/Services/MissionStoreSingleton.cs +++ b/src/Services/MissionStoreSingleton.cs @@ -119,20 +119,8 @@ public class MissionStoreSingleton { } } - // FIXME: Don't use BinaryFormatter for deep copying - // FIXME: Remove flag from the project file once we have a different way of deep copying public static Mission DeepCopy(Mission original) { - using (MemoryStream memoryStream = new MemoryStream()) { - BinaryFormatter formatter = new BinaryFormatter(); - - formatter.Serialize(memoryStream, original); - - memoryStream.Position = 0; - - Mission clone = (Mission)formatter.Deserialize(memoryStream); - - return clone; - } + return new Mission(original); } } diff --git a/src/sodoff.csproj b/src/sodoff.csproj index 83633a9..151699d 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -4,7 +4,6 @@ net9.0 enable enable - true USE_SQLITE;$(DefineConstants) USE_POSTGRESQL;$(DefineConstants) From 06daf21d8c870bb048e4ed731df9a5e0c3c95b81 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Thu, 26 Jun 2025 21:51:34 +0200 Subject: [PATCH 05/18] update dependencies --- src/sodoff.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sodoff.csproj b/src/sodoff.csproj index 151699d..70c7c4a 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -11,26 +11,26 @@ - + - + - + - + From 2aac24c37eb62929d213a71bed5ad9f80b82fe05 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Fri, 27 Jun 2025 14:17:05 +0200 Subject: [PATCH 06/18] fix indent --- src/Schema/AchievementReward.cs | 62 +++++------ src/Schema/BluePrint.cs | 12 +- src/Schema/BluePrintDeductibleConfig.cs | 14 +-- src/Schema/BluePrintSpecification.cs | 36 +++--- src/Schema/CompletionAction.cs | 4 +- src/Schema/ItemAttribute.cs | 8 +- src/Schema/ItemAvailability.cs | 8 +- src/Schema/ItemData.cs | 142 ++++++++++++------------ src/Schema/ItemDataCategory.cs | 12 +- src/Schema/ItemDataRelationship.cs | 20 ++-- src/Schema/ItemDataRollover.cs | 8 +- src/Schema/ItemDataTexture.cs | 16 +-- src/Schema/ItemPossibleStatsMap.cs | 16 +-- src/Schema/ItemSaleConfig.cs | 20 ++-- src/Schema/ItemStat.cs | 16 +-- src/Schema/ItemState.cs | 22 ++-- src/Schema/ItemStateCriteria.cs | 4 +- src/Schema/ItemStateRule.cs | 8 +- src/Schema/ItemStatsMap.cs | 12 +- src/Schema/Mission.cs | 4 +- src/Schema/MissionCriteria.cs | 2 +- src/Schema/MissionRule.cs | 2 +- src/Schema/Pair.cs | 16 +-- src/Schema/PairData.cs | 2 +- src/Schema/PrerequisiteItem.cs | 2 +- src/Schema/RuleItem.cs | 2 +- src/Schema/Stat.cs | 20 ++-- src/Schema/StatRangeMap.cs | 20 ++-- src/Schema/Task.cs | 2 +- src/Schema/UserItemData.cs | 40 +++---- 30 files changed, 276 insertions(+), 276 deletions(-) diff --git a/src/Schema/AchievementReward.cs b/src/Schema/AchievementReward.cs index 20f0a26..b6f4f48 100644 --- a/src/Schema/AchievementReward.cs +++ b/src/Schema/AchievementReward.cs @@ -5,11 +5,11 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "AR", Namespace = "")] [Serializable] public class AchievementReward { - public AchievementReward() {} + public AchievementReward() { } public AchievementReward(AchievementReward other) { - if (other.UserItem != null) - UserItem = new UserItemData(other.UserItem); + if (other.UserItem != null) + UserItem = new UserItemData(other.UserItem); Amount = other.Amount; PointTypeID = other.PointTypeID; @@ -26,45 +26,45 @@ public class AchievementReward { } [XmlElement(ElementName = "ui", IsNullable = true)] - public UserItemData UserItem { get; set; } + public UserItemData UserItem { get; set; } - [XmlElement(ElementName = "a")] - public int? Amount; + [XmlElement(ElementName = "a")] + public int? Amount; - [XmlElement(ElementName = "p", IsNullable = true)] - public AchievementPointTypes? PointTypeID; + [XmlElement(ElementName = "p", IsNullable = true)] + public AchievementPointTypes? PointTypeID; - [XmlElement(ElementName = "ii")] - public int ItemID; + [XmlElement(ElementName = "ii")] + public int ItemID; - [XmlElement(ElementName = "i", IsNullable = true)] - public Guid? EntityID; + [XmlElement(ElementName = "i", IsNullable = true)] + public Guid? EntityID; - [XmlElement(ElementName = "t")] - public int EntityTypeID; + [XmlElement(ElementName = "t")] + public int EntityTypeID; - [XmlElement(ElementName = "r")] - public int RewardID; + [XmlElement(ElementName = "r")] + public int RewardID; - [XmlElement(ElementName = "ai")] - public int AchievementID; + [XmlElement(ElementName = "ai")] + public int AchievementID; - [XmlElement(ElementName = "amulti")] - public bool AllowMultiple; + [XmlElement(ElementName = "amulti")] + public bool AllowMultiple; - [XmlElement(ElementName = "mina", IsNullable = true)] - public int? MinAmount; + [XmlElement(ElementName = "mina", IsNullable = true)] + public int? MinAmount; - [XmlElement(ElementName = "maxa", IsNullable = true)] - public int? MaxAmount; + [XmlElement(ElementName = "maxa", IsNullable = true)] + public int? MaxAmount; - [XmlElement(ElementName = "d", IsNullable = true)] - public DateTime? Date; + [XmlElement(ElementName = "d", IsNullable = true)] + public DateTime? Date; - [XmlElement(ElementName = "cid")] - public int CommonInventoryID; + [XmlElement(ElementName = "cid")] + public int CommonInventoryID; - public AchievementReward Clone() { - return (AchievementReward) this.MemberwiseClone(); - } + public AchievementReward Clone() { + return (AchievementReward)this.MemberwiseClone(); + } } diff --git a/src/Schema/BluePrint.cs b/src/Schema/BluePrint.cs index e7f81b8..47b48d9 100644 --- a/src/Schema/BluePrint.cs +++ b/src/Schema/BluePrint.cs @@ -6,7 +6,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "BP", Namespace = "", IsNullable = true)] [Serializable] public class BluePrint { - public BluePrint() {} + public BluePrint() { } public BluePrint(BluePrint other) { Deductibles = other.Deductibles.Select(d => new BluePrintDeductibleConfig(d)).ToList(); @@ -15,11 +15,11 @@ public class BluePrint { } [XmlElement(ElementName = "BPDC", IsNullable = true)] - public List Deductibles { get; set; } + public List Deductibles { get; set; } - [XmlElement(ElementName = "ING", IsNullable = false)] - public List Ingredients { get; set; } + [XmlElement(ElementName = "ING", IsNullable = false)] + public List Ingredients { get; set; } - [XmlElement(ElementName = "OUT", IsNullable = false)] - public List Outputs { get; set; } + [XmlElement(ElementName = "OUT", IsNullable = false)] + public List Outputs { get; set; } } diff --git a/src/Schema/BluePrintDeductibleConfig.cs b/src/Schema/BluePrintDeductibleConfig.cs index a83012c..e6ceb8c 100644 --- a/src/Schema/BluePrintDeductibleConfig.cs +++ b/src/Schema/BluePrintDeductibleConfig.cs @@ -15,14 +15,14 @@ public class BluePrintDeductibleConfig { } [XmlElement(ElementName = "BPIID", IsNullable = false)] - public int BluePrintItemID { get; set; } + public int BluePrintItemID { get; set; } - [XmlElement(ElementName = "DT", IsNullable = false)] - public DeductibleType DeductibleType { get; set; } + [XmlElement(ElementName = "DT", IsNullable = false)] + public DeductibleType DeductibleType { get; set; } - [XmlElement(ElementName = "IID", IsNullable = true)] - public int? ItemID { get; set; } + [XmlElement(ElementName = "IID", IsNullable = true)] + public int? ItemID { get; set; } - [XmlElement(ElementName = "QTY", IsNullable = false)] - public int Quantity { get; set; } + [XmlElement(ElementName = "QTY", IsNullable = false)] + public int Quantity { get; set; } } diff --git a/src/Schema/BluePrintSpecification.cs b/src/Schema/BluePrintSpecification.cs index 2851c8c..6146f1d 100644 --- a/src/Schema/BluePrintSpecification.cs +++ b/src/Schema/BluePrintSpecification.cs @@ -3,7 +3,7 @@ using System.Xml.Serialization; namespace sodoff.Schema; public class BluePrintSpecification { - public BluePrintSpecification() {} + public BluePrintSpecification() { } public BluePrintSpecification(BluePrintSpecification other) { BluePrintSpecID = other.BluePrintSpecID; @@ -17,30 +17,30 @@ public class BluePrintSpecification { } [XmlElement(ElementName = "BPSID", IsNullable = false)] - public int BluePrintSpecID { get; set; } + public int BluePrintSpecID { get; set; } - [XmlElement(ElementName = "BPIID", IsNullable = false)] - public int BluePrintItemID { get; set; } + [XmlElement(ElementName = "BPIID", IsNullable = false)] + public int BluePrintItemID { get; set; } - public bool ShouldSerializeBluePrintItemID() { return BluePrintItemID != 0; } + public bool ShouldSerializeBluePrintItemID() { return BluePrintItemID != 0; } - [XmlElement(ElementName = "IID", IsNullable = true)] - public int? ItemID { get; set; } + [XmlElement(ElementName = "IID", IsNullable = true)] + public int? ItemID { get; set; } - [XmlElement(ElementName = "CID", IsNullable = true)] - public int? CategoryID { get; set; } + [XmlElement(ElementName = "CID", IsNullable = true)] + public int? CategoryID { get; set; } - [XmlElement(ElementName = "IR", IsNullable = true)] - public ItemRarity? ItemRarity { get; set; } + [XmlElement(ElementName = "IR", IsNullable = true)] + public ItemRarity? ItemRarity { get; set; } - [XmlElement(ElementName = "T", IsNullable = true)] - public ItemTier? Tier { get; set; } + [XmlElement(ElementName = "T", IsNullable = true)] + public ItemTier? Tier { get; set; } - [XmlElement(ElementName = "QTY", IsNullable = false)] - public int Quantity { get; set; } + [XmlElement(ElementName = "QTY", IsNullable = false)] + public int Quantity { get; set; } - [XmlElement(ElementName = "ST", IsNullable = true)] - public SpecificationType? SpecificationType { get; set; } + [XmlElement(ElementName = "ST", IsNullable = true)] + public SpecificationType? SpecificationType { get; set; } - public bool ShouldSerializeSpecificationType() { return SpecificationType != null; } + public bool ShouldSerializeSpecificationType() { return SpecificationType != null; } } diff --git a/src/Schema/CompletionAction.cs b/src/Schema/CompletionAction.cs index 8e9e9e2..5d49da3 100644 --- a/src/Schema/CompletionAction.cs +++ b/src/Schema/CompletionAction.cs @@ -4,12 +4,12 @@ namespace sodoff.Schema; [Serializable] public class CompletionAction { - public CompletionAction() {} + public CompletionAction() { } public CompletionAction(CompletionAction other) { Transition = other.Transition; } [XmlElement(ElementName = "Transition")] - public StateTransition Transition; + public StateTransition Transition; } diff --git a/src/Schema/ItemAttribute.cs b/src/Schema/ItemAttribute.cs index a5c3056..bfa76d8 100644 --- a/src/Schema/ItemAttribute.cs +++ b/src/Schema/ItemAttribute.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "AT", Namespace = "")] [Serializable] public class ItemAttribute { - public ItemAttribute() {} + public ItemAttribute() { } public ItemAttribute(ItemAttribute other) { Key = other.Key; @@ -13,8 +13,8 @@ public class ItemAttribute { } [XmlElement(ElementName = "k")] - public string Key; + public string Key; - [XmlElement(ElementName = "v")] - public string Value; + [XmlElement(ElementName = "v")] + public string Value; } diff --git a/src/Schema/ItemAvailability.cs b/src/Schema/ItemAvailability.cs index 898a666..3b79bc6 100644 --- a/src/Schema/ItemAvailability.cs +++ b/src/Schema/ItemAvailability.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Availability", Namespace = "")] [Serializable] public class ItemAvailability { - public ItemAvailability() {} + public ItemAvailability() { } public ItemAvailability(ItemAvailability other) { StartDate = other.StartDate; @@ -13,8 +13,8 @@ public class ItemAvailability { } [XmlElement(ElementName = "sdate", IsNullable = true)] - public DateTime? StartDate; + public DateTime? StartDate; - [XmlElement(ElementName = "edate", IsNullable = true)] - public DateTime? EndDate; + [XmlElement(ElementName = "edate", IsNullable = true)] + public DateTime? EndDate; } diff --git a/src/Schema/ItemData.cs b/src/Schema/ItemData.cs index c8b591a..73c5762 100644 --- a/src/Schema/ItemData.cs +++ b/src/Schema/ItemData.cs @@ -4,7 +4,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "I", Namespace = "", IsNullable = true)] public class ItemData { - public ItemData() {} + public ItemData() { } public ItemData(ItemData other) { ItemStates = other.ItemStates.Select(s => new ItemState(s)).ToList(); @@ -43,108 +43,108 @@ public class ItemData { } [XmlElement(ElementName = "is")] - public List ItemStates { get; set; } + public List ItemStates { get; set; } - [XmlElement(ElementName = "ir", IsNullable = true)] - public ItemRarity? ItemRarity { get; set; } + [XmlElement(ElementName = "ir", IsNullable = true)] + public ItemRarity? ItemRarity { get; set; } - [XmlElement(ElementName = "ipsm", IsNullable = true)] - public ItemPossibleStatsMap PossibleStatsMap { get; set; } + [XmlElement(ElementName = "ipsm", IsNullable = true)] + public ItemPossibleStatsMap PossibleStatsMap { get; set; } - [XmlElement(ElementName = "ism", IsNullable = true)] - public ItemStatsMap ItemStatsMap { get; set; } + [XmlElement(ElementName = "ism", IsNullable = true)] + public ItemStatsMap ItemStatsMap { get; set; } - [XmlElement(ElementName = "iscs", IsNullable = true)] - public ItemSaleConfig[] ItemSaleConfigs { get; set; } + [XmlElement(ElementName = "iscs", IsNullable = true)] + public ItemSaleConfig[] ItemSaleConfigs { get; set; } - [XmlElement(ElementName = "bp", IsNullable = true)] - public BluePrint BluePrint { get; set; } + [XmlElement(ElementName = "bp", IsNullable = true)] + public BluePrint BluePrint { get; set; } - [XmlElement(ElementName = "an")] - public string AssetName; + [XmlElement(ElementName = "an")] + public string AssetName; - [XmlElement(ElementName = "at", IsNullable = true)] - public ItemAttribute[] Attribute; + [XmlElement(ElementName = "at", IsNullable = true)] + public ItemAttribute[] Attribute; - [XmlElement(ElementName = "c")] - public ItemDataCategory[] Category; + [XmlElement(ElementName = "c")] + public ItemDataCategory[] Category; - [XmlElement(ElementName = "ct")] - public int Cost; + [XmlElement(ElementName = "ct")] + public int Cost; - [XmlElement(ElementName = "ct2")] - public int CashCost; + [XmlElement(ElementName = "ct2")] + public int CashCost; - [XmlElement(ElementName = "cp")] - public int CreativePoints; + [XmlElement(ElementName = "cp")] + public int CreativePoints; - [XmlElement(ElementName = "d")] - public string Description; + [XmlElement(ElementName = "d")] + public string Description; - [XmlElement(ElementName = "icn")] - public string IconName; + [XmlElement(ElementName = "icn")] + public string IconName; - [XmlElement(ElementName = "im")] - public int InventoryMax; + [XmlElement(ElementName = "im")] + public int InventoryMax; - [XmlElement(ElementName = "id")] - public int ItemID; + [XmlElement(ElementName = "id")] + public int ItemID; - [XmlElement(ElementName = "itn")] - public string ItemName; + [XmlElement(ElementName = "itn")] + public string ItemName; - [XmlElement(ElementName = "itnp")] - public string ItemNamePlural; + [XmlElement(ElementName = "itnp")] + public string ItemNamePlural; - [XmlElement(ElementName = "l")] - public bool Locked; + [XmlElement(ElementName = "l")] + public bool Locked; - [XmlElement(ElementName = "g", IsNullable = true)] - public string Geometry2; + [XmlElement(ElementName = "g", IsNullable = true)] + public string Geometry2; - [XmlElement(ElementName = "ro", IsNullable = true)] - public ItemDataRollover Rollover; + [XmlElement(ElementName = "ro", IsNullable = true)] + public ItemDataRollover Rollover; - [XmlElement(ElementName = "rid", IsNullable = true)] - public int? RankId; + [XmlElement(ElementName = "rid", IsNullable = true)] + public int? RankId; - [XmlElement(ElementName = "r")] - public ItemDataRelationship[] Relationship; + [XmlElement(ElementName = "r")] + public ItemDataRelationship[] Relationship; - [XmlElement(ElementName = "s")] - public bool Stackable; + [XmlElement(ElementName = "s")] + public bool Stackable; - [XmlElement(ElementName = "as")] - public bool AllowStacking; + [XmlElement(ElementName = "as")] + public bool AllowStacking; - [XmlElement(ElementName = "sf")] - public int SaleFactor; + [XmlElement(ElementName = "sf")] + public int SaleFactor; - [XmlElement(ElementName = "t")] - public ItemDataTexture[] Texture; + [XmlElement(ElementName = "t")] + public ItemDataTexture[] Texture; - [XmlElement(ElementName = "u")] - public int Uses; + [XmlElement(ElementName = "u")] + public int Uses; - [XmlElement(ElementName = "av")] - public ItemAvailability[] Availability; + [XmlElement(ElementName = "av")] + public ItemAvailability[] Availability; - [XmlElement(ElementName = "rtid")] - public int RewardTypeID; + [XmlElement(ElementName = "rtid")] + public int RewardTypeID; - [XmlElement(ElementName = "p", IsNullable = true)] - public int? Points; + [XmlElement(ElementName = "p", IsNullable = true)] + public int? Points; - [XmlIgnore] - public float NormalDiscoutModifier; + [XmlIgnore] + public float NormalDiscoutModifier; - [XmlIgnore] - public float MemberDiscountModifier; + [XmlIgnore] + public float MemberDiscountModifier; - [XmlIgnore] - public float FinalDiscoutModifier { - get { - return Math.Min(1f, (1f - NormalDiscoutModifier) * (1f - MemberDiscountModifier)); + [XmlIgnore] + public float FinalDiscoutModifier { + get { + return Math.Min(1f, (1f - NormalDiscoutModifier) * (1f - MemberDiscountModifier)); } - } + } } diff --git a/src/Schema/ItemDataCategory.cs b/src/Schema/ItemDataCategory.cs index 6e5cb55..d9b31b6 100644 --- a/src/Schema/ItemDataCategory.cs +++ b/src/Schema/ItemDataCategory.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IC", Namespace = "")] [Serializable] public class ItemDataCategory { - public ItemDataCategory() {} + public ItemDataCategory() { } public ItemDataCategory(ItemDataCategory other) { CategoryId = other.CategoryId; @@ -14,11 +14,11 @@ public class ItemDataCategory { } [XmlElement(ElementName = "cid")] - public int CategoryId; + public int CategoryId; - [XmlElement(ElementName = "cn")] - public string CategoryName; + [XmlElement(ElementName = "cn")] + public string CategoryName; - [XmlElement(ElementName = "i", IsNullable = true)] - public string IconName; + [XmlElement(ElementName = "i", IsNullable = true)] + public string IconName; } diff --git a/src/Schema/ItemDataRelationship.cs b/src/Schema/ItemDataRelationship.cs index f340ecf..58c0817 100644 --- a/src/Schema/ItemDataRelationship.cs +++ b/src/Schema/ItemDataRelationship.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IRE", Namespace = "")] [Serializable] public class ItemDataRelationship { - public ItemDataRelationship() {} + public ItemDataRelationship() { } public ItemDataRelationship(ItemDataRelationship other) { Type = other.Type; @@ -16,17 +16,17 @@ public class ItemDataRelationship { } [XmlElement(ElementName = "t")] - public string Type; + public string Type; - [XmlElement(ElementName = "id")] - public int ItemId; + [XmlElement(ElementName = "id")] + public int ItemId; - [XmlElement(ElementName = "wt")] - public int Weight; + [XmlElement(ElementName = "wt")] + public int Weight; - [XmlElement(ElementName = "q")] - public int Quantity; + [XmlElement(ElementName = "q")] + public int Quantity; - [XmlElement(ElementName = "mxq")] - public int? MaxQuantity; + [XmlElement(ElementName = "mxq")] + public int? MaxQuantity; } diff --git a/src/Schema/ItemDataRollover.cs b/src/Schema/ItemDataRollover.cs index baee86f..7e03179 100644 --- a/src/Schema/ItemDataRollover.cs +++ b/src/Schema/ItemDataRollover.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IRO", Namespace = "")] [Serializable] public class ItemDataRollover { - public ItemDataRollover() {} + public ItemDataRollover() { } public ItemDataRollover(ItemDataRollover other) { DialogName = other.DialogName; @@ -13,8 +13,8 @@ public class ItemDataRollover { } [XmlElement(ElementName = "d")] - public string DialogName; + public string DialogName; - [XmlElement(ElementName = "b")] - public string Bundle; + [XmlElement(ElementName = "b")] + public string Bundle; } diff --git a/src/Schema/ItemDataTexture.cs b/src/Schema/ItemDataTexture.cs index 1650352..053d109 100644 --- a/src/Schema/ItemDataTexture.cs +++ b/src/Schema/ItemDataTexture.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IT", Namespace = "")] [Serializable] public class ItemDataTexture { - public ItemDataTexture() {} + public ItemDataTexture() { } public ItemDataTexture(ItemDataTexture other) { TextureName = other.TextureName; @@ -15,14 +15,14 @@ public class ItemDataTexture { } [XmlElement(ElementName = "n")] - public string TextureName; + public string TextureName; - [XmlElement(ElementName = "t")] - public string TextureTypeName; + [XmlElement(ElementName = "t")] + public string TextureTypeName; - [XmlElement(ElementName = "x", IsNullable = true)] - public float? OffsetX; + [XmlElement(ElementName = "x", IsNullable = true)] + public float? OffsetX; - [XmlElement(ElementName = "y", IsNullable = true)] - public float? OffsetY; + [XmlElement(ElementName = "y", IsNullable = true)] + public float? OffsetY; } diff --git a/src/Schema/ItemPossibleStatsMap.cs b/src/Schema/ItemPossibleStatsMap.cs index ac577b0..4070725 100644 --- a/src/Schema/ItemPossibleStatsMap.cs +++ b/src/Schema/ItemPossibleStatsMap.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IPSM", Namespace = "", IsNullable = false)] [Serializable] public class ItemPossibleStatsMap { - public ItemPossibleStatsMap() {} + public ItemPossibleStatsMap() { } public ItemPossibleStatsMap(ItemPossibleStatsMap other) { ItemID = other.ItemID; @@ -15,14 +15,14 @@ public class ItemPossibleStatsMap { } [XmlElement(ElementName = "IID", IsNullable = false)] - public int ItemID { get; set; } + public int ItemID { get; set; } - [XmlElement(ElementName = "SC", IsNullable = false)] - public int ItemStatsCount { get; set; } + [XmlElement(ElementName = "SC", IsNullable = false)] + public int ItemStatsCount { get; set; } - [XmlElement(ElementName = "SID", IsNullable = false)] - public int SetID { get; set; } + [XmlElement(ElementName = "SID", IsNullable = false)] + public int SetID { get; set; } - [XmlElement(ElementName = "SS", IsNullable = false)] - public List Stats { get; set; } + [XmlElement(ElementName = "SS", IsNullable = false)] + public List Stats { get; set; } } diff --git a/src/Schema/ItemSaleConfig.cs b/src/Schema/ItemSaleConfig.cs index 0528167..c7644e6 100644 --- a/src/Schema/ItemSaleConfig.cs +++ b/src/Schema/ItemSaleConfig.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ISC", Namespace = "", IsNullable = true)] [Serializable] public class ItemSaleConfig { - public ItemSaleConfig() {} + public ItemSaleConfig() { } public ItemSaleConfig(ItemSaleConfig other) { ItemID = other.ItemID; @@ -16,17 +16,17 @@ public class ItemSaleConfig { } [XmlElement(ElementName = "IID", IsNullable = true)] - public int? ItemID { get; set; } + public int? ItemID { get; set; } - [XmlElement(ElementName = "CID", IsNullable = true)] - public int? CategoryID { get; set; } + [XmlElement(ElementName = "CID", IsNullable = true)] + public int? CategoryID { get; set; } - [XmlElement(ElementName = "RID", IsNullable = true)] - public int? RarityID { get; set; } + [XmlElement(ElementName = "RID", IsNullable = true)] + public int? RarityID { get; set; } - [XmlElement(ElementName = "QTY", IsNullable = false)] - public int Quantity { get; set; } + [XmlElement(ElementName = "QTY", IsNullable = false)] + public int Quantity { get; set; } - [XmlElement(ElementName = "RIID", IsNullable = false)] - public int RewardItemID { get; set; } + [XmlElement(ElementName = "RIID", IsNullable = false)] + public int RewardItemID { get; set; } } diff --git a/src/Schema/ItemStat.cs b/src/Schema/ItemStat.cs index 3a1b9c0..3782a33 100644 --- a/src/Schema/ItemStat.cs +++ b/src/Schema/ItemStat.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "IS", Namespace = "")] [Serializable] public class ItemStat { - public ItemStat() {} + public ItemStat() { } public ItemStat(ItemStat other) { ItemStatID = other.ItemStatID; @@ -15,14 +15,14 @@ public class ItemStat { } [XmlElement(ElementName = "ID")] - public int ItemStatID { get; set; } + public int ItemStatID { get; set; } - [XmlElement(ElementName = "N")] - public string Name { get; set; } + [XmlElement(ElementName = "N")] + public string Name { get; set; } - [XmlElement(ElementName = "V")] - public string Value { get; set; } + [XmlElement(ElementName = "V")] + public string Value { get; set; } - [XmlElement(ElementName = "DTI")] - public DataTypeInfo DataType { get; set; } + [XmlElement(ElementName = "DTI")] + public DataTypeInfo DataType { get; set; } } diff --git a/src/Schema/ItemState.cs b/src/Schema/ItemState.cs index a39af77..3d90ab4 100644 --- a/src/Schema/ItemState.cs +++ b/src/Schema/ItemState.cs @@ -17,20 +17,20 @@ public class ItemState { } [XmlElement(ElementName = "ItemStateID")] - public int ItemStateID; + public int ItemStateID; - [XmlElement(ElementName = "Name")] - public string Name; + [XmlElement(ElementName = "Name")] + public string Name; - [XmlElement(ElementName = "Rule")] - public ItemStateRule Rule; + [XmlElement(ElementName = "Rule")] + public ItemStateRule Rule; - [XmlElement(ElementName = "Order")] - public int Order; + [XmlElement(ElementName = "Order")] + public int Order; - [XmlElement(ElementName = "AchievementID", IsNullable = true)] - public int? AchievementID; + [XmlElement(ElementName = "AchievementID", IsNullable = true)] + public int? AchievementID; - [XmlElement(ElementName = "Rewards")] - public AchievementReward[] Rewards; + [XmlElement(ElementName = "Rewards")] + public AchievementReward[] Rewards; } diff --git a/src/Schema/ItemStateCriteria.cs b/src/Schema/ItemStateCriteria.cs index 715946f..5a482c4 100644 --- a/src/Schema/ItemStateCriteria.cs +++ b/src/Schema/ItemStateCriteria.cs @@ -11,12 +11,12 @@ namespace sodoff.Schema; [XmlInclude(typeof(ItemStateCriteriaExpiry))] [Serializable] public class ItemStateCriteria { - public ItemStateCriteria() {} + public ItemStateCriteria() { } public ItemStateCriteria(ItemStateCriteria other) { Type = other.Type; } [XmlElement(ElementName = "Type")] - public ItemStateCriteriaType Type; + public ItemStateCriteriaType Type; } diff --git a/src/Schema/ItemStateRule.cs b/src/Schema/ItemStateRule.cs index 162efb4..e8eac05 100644 --- a/src/Schema/ItemStateRule.cs +++ b/src/Schema/ItemStateRule.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ItemStateRule", Namespace = "")] [Serializable] public class ItemStateRule { - public ItemStateRule() {} + public ItemStateRule() { } public ItemStateRule(ItemStateRule other) { Criterias = other.Criterias.Select(c => new ItemStateCriteria(c)).ToList(); @@ -13,8 +13,8 @@ public class ItemStateRule { } [XmlElement(ElementName = "Criterias")] - public List Criterias; + public List Criterias; - [XmlElement(ElementName = "CompletionAction")] - public CompletionAction CompletionAction; + [XmlElement(ElementName = "CompletionAction")] + public CompletionAction CompletionAction; } diff --git a/src/Schema/ItemStatsMap.cs b/src/Schema/ItemStatsMap.cs index 280500a..f694446 100644 --- a/src/Schema/ItemStatsMap.cs +++ b/src/Schema/ItemStatsMap.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "ISM", Namespace = "", IsNullable = false)] [Serializable] public class ItemStatsMap { - public ItemStatsMap() {} + public ItemStatsMap() { } public ItemStatsMap(ItemStatsMap other) { ItemID = other.ItemID; @@ -14,11 +14,11 @@ public class ItemStatsMap { } [XmlElement(ElementName = "IID", IsNullable = false)] - public int ItemID { get; set; } + public int ItemID { get; set; } - [XmlElement(ElementName = "IT", IsNullable = false)] - public ItemTier ItemTier { get; set; } + [XmlElement(ElementName = "IT", IsNullable = false)] + public ItemTier ItemTier { get; set; } - [XmlElement(ElementName = "ISS", IsNullable = false)] - public ItemStat[] ItemStats { get; set; } + [XmlElement(ElementName = "ISS", IsNullable = false)] + public ItemStat[] ItemStats { get; set; } } diff --git a/src/Schema/Mission.cs b/src/Schema/Mission.cs index 1e49c29..278e4ce 100644 --- a/src/Schema/Mission.cs +++ b/src/Schema/Mission.cs @@ -3,9 +3,9 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Mission", Namespace = "")] -[Serializable] // FIXME: Remove serializable once we have a different way of deep copying than BinaryFormatter +[Serializable] public class Mission { - public Mission() {} + public Mission() { } public Mission(Mission other) { if (other == null) throw new ArgumentNullException(nameof(other)); diff --git a/src/Schema/MissionCriteria.cs b/src/Schema/MissionCriteria.cs index 29c867f..154a6ee 100644 --- a/src/Schema/MissionCriteria.cs +++ b/src/Schema/MissionCriteria.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "MissionCriteria", Namespace = "")] [Serializable] public class MissionCriteria { - public MissionCriteria() {} + public MissionCriteria() { } public MissionCriteria(MissionCriteria other) { Type = other.Type; diff --git a/src/Schema/MissionRule.cs b/src/Schema/MissionRule.cs index 3a9e6a5..d34905b 100644 --- a/src/Schema/MissionRule.cs +++ b/src/Schema/MissionRule.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "MissionRule", Namespace = "")] [Serializable] public class MissionRule { - public MissionRule() {} + public MissionRule() { } public MissionRule(MissionRule other) { Prerequisites = other.Prerequisites.Select(p => new PrerequisiteItem(p)).ToList(); diff --git a/src/Schema/Pair.cs b/src/Schema/Pair.cs index 485d3d8..c100b2f 100644 --- a/src/Schema/Pair.cs +++ b/src/Schema/Pair.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Pair", Namespace = "")] [Serializable] public class Pair { - public Pair() {} + public Pair() { } public Pair(Pair other) { PairKey = other.PairKey; @@ -14,11 +14,11 @@ public class Pair { } [XmlElement(ElementName = "PairKey")] - public string PairKey; - - [XmlElement(ElementName = "PairValue")] - public string PairValue; - - [XmlElement(ElementName = "UpdateDate")] - public DateTime UpdateDate; + public string PairKey; + + [XmlElement(ElementName = "PairValue")] + public string PairValue; + + [XmlElement(ElementName = "UpdateDate")] + public DateTime UpdateDate; } \ No newline at end of file diff --git a/src/Schema/PairData.cs b/src/Schema/PairData.cs index 46438ff..8b7d995 100644 --- a/src/Schema/PairData.cs +++ b/src/Schema/PairData.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Pairs", Namespace = "", IsNullable = true)] [Serializable] public class PairData { - public PairData() {} + public PairData() { } public PairData(PairData other) { Pairs = other.Pairs.Select(p => new Pair(p)).ToArray(); diff --git a/src/Schema/PrerequisiteItem.cs b/src/Schema/PrerequisiteItem.cs index 8d555a4..11fb74f 100644 --- a/src/Schema/PrerequisiteItem.cs +++ b/src/Schema/PrerequisiteItem.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "PrerequisiteItem", Namespace = "")] [Serializable] public class PrerequisiteItem { - public PrerequisiteItem() {} + public PrerequisiteItem() { } public PrerequisiteItem(PrerequisiteItem other) { Type = other.Type; diff --git a/src/Schema/RuleItem.cs b/src/Schema/RuleItem.cs index 3478454..ac4fcd1 100644 --- a/src/Schema/RuleItem.cs +++ b/src/Schema/RuleItem.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "RuleItem", Namespace = "")] [Serializable] public class RuleItem { - public RuleItem() {} + public RuleItem() { } public RuleItem(RuleItem other) { Type = other.Type; diff --git a/src/Schema/Stat.cs b/src/Schema/Stat.cs index ea9fc3a..23fd6f0 100644 --- a/src/Schema/Stat.cs +++ b/src/Schema/Stat.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "STAT", Namespace = "", IsNullable = false)] [Serializable] public class Stat { - public Stat() {} + public Stat() { } public Stat(Stat other) { ItemID = other.ItemID; @@ -16,17 +16,17 @@ public class Stat { } [XmlElement(ElementName = "IID", IsNullable = false)] - public int ItemID { get; set; } + public int ItemID { get; set; } - [XmlElement(ElementName = "ISID", IsNullable = false)] - public int ItemStatsID { get; set; } + [XmlElement(ElementName = "ISID", IsNullable = false)] + public int ItemStatsID { get; set; } - [XmlElement(ElementName = "SID", IsNullable = false)] - public int SetID { get; set; } + [XmlElement(ElementName = "SID", IsNullable = false)] + public int SetID { get; set; } - [XmlElement(ElementName = "PROB", IsNullable = false)] - public int Probability { get; set; } + [XmlElement(ElementName = "PROB", IsNullable = false)] + public int Probability { get; set; } - [XmlElement(ElementName = "ISRM", IsNullable = false)] - public List ItemStatsRangeMaps { get; set; } + [XmlElement(ElementName = "ISRM", IsNullable = false)] + public List ItemStatsRangeMaps { get; set; } } diff --git a/src/Schema/StatRangeMap.cs b/src/Schema/StatRangeMap.cs index 6b8c7c5..0f27ce9 100644 --- a/src/Schema/StatRangeMap.cs +++ b/src/Schema/StatRangeMap.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "SRM", Namespace = "", IsNullable = false)] [Serializable] public class StatRangeMap { - public StatRangeMap() {} + public StatRangeMap() { } public StatRangeMap(StatRangeMap other) { ItemStatsID = other.ItemStatsID; @@ -16,17 +16,17 @@ public class StatRangeMap { } [XmlElement(ElementName = "ISID", IsNullable = false)] - public int ItemStatsID { get; set; } + public int ItemStatsID { get; set; } - [XmlElement(ElementName = "ISN", IsNullable = false)] - public string ItemStatsName { get; set; } + [XmlElement(ElementName = "ISN", IsNullable = false)] + public string ItemStatsName { get; set; } - [XmlElement(ElementName = "ITID", IsNullable = false)] - public int ItemTierID { get; set; } + [XmlElement(ElementName = "ITID", IsNullable = false)] + public int ItemTierID { get; set; } - [XmlElement(ElementName = "SR", IsNullable = false)] - public int StartRange { get; set; } + [XmlElement(ElementName = "SR", IsNullable = false)] + public int StartRange { get; set; } - [XmlElement(ElementName = "ER", IsNullable = false)] - public int EndRange { get; set; } + [XmlElement(ElementName = "ER", IsNullable = false)] + public int EndRange { get; set; } } diff --git a/src/Schema/Task.cs b/src/Schema/Task.cs index f0f19b6..e909f21 100644 --- a/src/Schema/Task.cs +++ b/src/Schema/Task.cs @@ -8,7 +8,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "Task", Namespace = "")] [Serializable] public class Task { - public Task() {} + public Task() { } public Task(Task other) { TaskID = other.TaskID; diff --git a/src/Schema/UserItemData.cs b/src/Schema/UserItemData.cs index 1e52f1c..4974e42 100644 --- a/src/Schema/UserItemData.cs +++ b/src/Schema/UserItemData.cs @@ -5,7 +5,7 @@ namespace sodoff.Schema; [XmlRoot(ElementName = "UserItem", Namespace = "")] [Serializable] public class UserItemData { - public UserItemData() {} + public UserItemData() { } public UserItemData(UserItemData other) { ItemID = other.ItemID; @@ -21,32 +21,32 @@ public class UserItemData { } [XmlElement(ElementName = "iid")] - public int ItemID { get; set; } + public int ItemID { get; set; } - [XmlElement(ElementName = "md", IsNullable = true)] - public DateTime? ModifiedDate { get; set; } + [XmlElement(ElementName = "md", IsNullable = true)] + public DateTime? ModifiedDate { get; set; } - [XmlElement(ElementName = "uia", IsNullable = true)] - public PairData UserItemAttributes { get; set; } + [XmlElement(ElementName = "uia", IsNullable = true)] + public PairData UserItemAttributes { get; set; } - [XmlElement(ElementName = "iss", IsNullable = true)] - public ItemStat[] ItemStats { get; set; } + [XmlElement(ElementName = "iss", IsNullable = true)] + public ItemStat[] ItemStats { get; set; } - [XmlElement(ElementName = "IT", IsNullable = true)] - public ItemTier? ItemTier { get; set; } + [XmlElement(ElementName = "IT", IsNullable = true)] + public ItemTier? ItemTier { get; set; } - [XmlElement(ElementName = "cd", IsNullable = true)] - public DateTime? CreatedDate { get; set; } + [XmlElement(ElementName = "cd", IsNullable = true)] + public DateTime? CreatedDate { get; set; } - [XmlElement(ElementName = "uiid")] - public int UserInventoryID; + [XmlElement(ElementName = "uiid")] + public int UserInventoryID; - [XmlElement(ElementName = "q")] - public int Quantity; + [XmlElement(ElementName = "q")] + public int Quantity; - [XmlElement(ElementName = "u")] - public int Uses; + [XmlElement(ElementName = "u")] + public int Uses; - [XmlElement(ElementName = "i")] - public ItemData Item; + [XmlElement(ElementName = "i")] + public ItemData Item; } From a3db9c2bcf19396c47e37e8422577e02967335bf Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Fri, 27 Jun 2025 14:37:19 +0000 Subject: [PATCH 07/18] update dotnet version in Dockerfile --- src/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Dockerfile b/src/Dockerfile index e4fc8a9..8c3d2e5 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -1,5 +1,5 @@ # Use the official .NET SDK image for building the application -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /src # Copy the source code @@ -13,7 +13,7 @@ RUN mv src/mods /app && ln -s /app/mods src/ RUN mv src/assets /app && ln -s /app/assets src/ # Create clean run environment (without source and sdk) -# FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +# FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base # WORKDIR /app # COPY --from=build /app . From 12bb663076dab4b6091628b7b2b2f3037a174208 Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Fri, 27 Jun 2025 14:46:23 +0000 Subject: [PATCH 08/18] fix null exception in LoginParent --- src/Controllers/Common/AuthenticationController.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Controllers/Common/AuthenticationController.cs b/src/Controllers/Common/AuthenticationController.cs index 465680a..96e1065 100644 --- a/src/Controllers/Common/AuthenticationController.cs +++ b/src/Controllers/Common/AuthenticationController.cs @@ -48,8 +48,13 @@ public class AuthenticationController : Controller { } else { user = ctx.Users.FirstOrDefault(e => e.Username == data.UserName); } + + if (user is null) { + return Ok(new ParentLoginInfo { Status = MembershipUserStatus.InvalidUserName }); + } + PasswordVerificationResult result = new PasswordHasher().VerifyHashedPassword(null, user.Password, data.Password); - if (user is null || result == PasswordVerificationResult.Failed) { + if (result == PasswordVerificationResult.Failed) { return Ok(new ParentLoginInfo { Status = MembershipUserStatus.InvalidPassword }); } From bca383c4d0e2683ba0f18f00effa4649a545dca6 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Mon, 30 Jun 2025 15:26:47 +0200 Subject: [PATCH 09/18] remove PairData.Update this is expensive and unnecessary because the entity is already tracked --- src/Services/KeyValueService.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Services/KeyValueService.cs b/src/Services/KeyValueService.cs index 1144108..9eb85c7 100644 --- a/src/Services/KeyValueService.cs +++ b/src/Services/KeyValueService.cs @@ -50,9 +50,7 @@ public class KeyValueService { } } - if (exists) - ctx.PairData.Update(pair); - else + if (!exists) ctx.PairData.Add(pair); ctx.SaveChanges(); From 7dbcc456b98046ffc734d38aba7ee926389ceb8f Mon Sep 17 00:00:00 2001 From: Spirtix Date: Mon, 30 Jun 2025 19:33:49 +0200 Subject: [PATCH 10/18] async locking for VikingSession --- src/Attributes/VikingSession.cs | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Attributes/VikingSession.cs b/src/Attributes/VikingSession.cs index e93eb2b..044adaf 100644 --- a/src/Attributes/VikingSession.cs +++ b/src/Attributes/VikingSession.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using sodoff.Model; namespace sodoff.Attributes; @@ -12,6 +13,9 @@ public class VikingSession : Attribute, IAsyncActionFilter { public Modes Mode { get; set; } = Modes.VIKING; public bool UseLock = false; + private static Dictionary semaphores = new(); + private static SemaphoreSlim dictSemaphore = new(1, 1); + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { DBContext ctx = context.HttpContext.RequestServices.GetService(typeof(DBContext)) as DBContext; @@ -22,7 +26,7 @@ public class VikingSession : Attribute, IAsyncActionFilter { return; } - Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == Guid.Parse(context.HttpContext.Request.Form[ApiToken].ToString())); + Session? session = await ctx.Sessions.FirstOrDefaultAsync(x => x.ApiToken == Guid.Parse(context.HttpContext.Request.Form[ApiToken].ToString())); // get viking / user id from session @@ -44,15 +48,16 @@ public class VikingSession : Attribute, IAsyncActionFilter { // NOTE: we can't refer to session.User / session.Viking here, // because it may cause to ignore modifications from the threads we are waiting for // we can use its only after vikingMutex.WaitOne() - - Mutex vikingMutex = new Mutex(false, "SoDOffViking:" + userVikingId); + string semKey = "SoDOffViking:" + userVikingId; + SemaphoreSlim semaphore = await GetSemaphore(semKey); try { - vikingMutex.WaitOne(); + await semaphore.WaitAsync(); context.ActionArguments["user"] = session.User; context.ActionArguments["viking"] = session.Viking; await next(); } finally { - vikingMutex.ReleaseMutex(); + semaphore.Release(); + await RemoveSemaphore(semKey, semaphore); } } else { context.ActionArguments["user"] = session.User; @@ -60,4 +65,22 @@ public class VikingSession : Attribute, IAsyncActionFilter { await next(); } } + + private static async Task GetSemaphore(string key) { + await dictSemaphore.WaitAsync(); + if (!semaphores.TryGetValue(key, out SemaphoreSlim semaphore)) { + semaphore = new SemaphoreSlim(1, 1); + semaphores.Add(key, semaphore); + } + dictSemaphore.Release(); + return semaphore; + } + + private static async Task RemoveSemaphore(string key, SemaphoreSlim sem) { + await dictSemaphore.WaitAsync(); + if (sem.CurrentCount == 1) { + semaphores.Remove(key); + } + dictSemaphore.Release(); + } } From 1b22c9c3ddd92e482d20eefe466622d37d7ac4d3 Mon Sep 17 00:00:00 2001 From: Spirtix Date: Mon, 30 Jun 2025 22:21:10 +0200 Subject: [PATCH 11/18] remove async query --- src/Attributes/VikingSession.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Attributes/VikingSession.cs b/src/Attributes/VikingSession.cs index 044adaf..8cdb829 100644 --- a/src/Attributes/VikingSession.cs +++ b/src/Attributes/VikingSession.cs @@ -26,7 +26,7 @@ public class VikingSession : Attribute, IAsyncActionFilter { return; } - Session? session = await ctx.Sessions.FirstOrDefaultAsync(x => x.ApiToken == Guid.Parse(context.HttpContext.Request.Form[ApiToken].ToString())); + Session? session = ctx.Sessions.FirstOrDefault(x => x.ApiToken == Guid.Parse(context.HttpContext.Request.Form[ApiToken].ToString())); // get viking / user id from session From 0923b80cdf7df5972b880ecb8be9d52fc142af2d Mon Sep 17 00:00:00 2001 From: Spirtix Date: Tue, 1 Jul 2025 16:40:56 +0200 Subject: [PATCH 12/18] lock CreatePet and SetImage --- src/Controllers/Common/ContentController.cs | 10 +++------- src/appsettings.json | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index 49e0f18..6c72812 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -570,7 +570,7 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("V2/ContentWebService.asmx/CreatePet")] - [VikingSession] + [VikingSession(UseLock = true)] public IActionResult CreatePet(Viking viking, [FromForm] string request) { RaisedPetRequest raisedPetRequest = XmlUtil.DeserializeXml(request); // TODO: Investigate SetAsSelectedPet and UnSelectOtherPets - they don't seem to do anything @@ -602,7 +602,6 @@ public class ContentController : Controller { if (raisedPetRequest.SetAsSelectedPet == true) { viking.SelectedDragon = dragon; - ctx.Update(viking); } ctx.Dragons.Add(dragon); ctx.Images.Add(image); @@ -905,7 +904,7 @@ public class ContentController : Controller { [HttpPost] [Produces("application/xml")] [Route("ContentWebService.asmx/SetImage")] - [VikingSession] + [VikingSession(UseLock = true)] public bool SetImage(Viking viking, [FromForm] string ImageType, [FromForm] int ImageSlot, [FromForm] string contentXML, [FromForm] string imageFile) { // TODO: the other properties of contentXML ImageData data = XmlUtil.DeserializeXml(contentXML); @@ -925,11 +924,8 @@ public class ContentController : Controller { image.ImageData = imageFile; image.TemplateName = data.TemplateName; - if (newImage) { + if (newImage) ctx.Images.Add(image); - } else { - ctx.Images.Update(image); - } ctx.SaveChanges(); return true; diff --git a/src/appsettings.json b/src/appsettings.json index de5849a..32c1f6c 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -74,7 +74,7 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft.AspNetCore": "Information" } }, "AllowedHosts": "*" From 1a6db72d7a542c424f16d93b8f68f40ab5ea23de Mon Sep 17 00:00:00 2001 From: Spirtix Date: Wed, 2 Jul 2025 21:28:53 +0200 Subject: [PATCH 13/18] downgrade ef to 7 There's a performance regression for synchronous insert/update in npgsql ef adapter, we'll have to switch to asynchronous db calls before updating --- src/sodoff.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sodoff.csproj b/src/sodoff.csproj index 70c7c4a..68159ae 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -11,26 +11,26 @@ - + - + - + - + From 278f04d38134650d6f73ef52dcc926c56fedb555 Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Sun, 27 Jul 2025 10:30:34 +0000 Subject: [PATCH 14/18] disable null-related warnings --- src/sodoff.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sodoff.csproj b/src/sodoff.csproj index 68159ae..cab8f4d 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -8,6 +8,8 @@ USE_SQLITE;$(DefineConstants) USE_POSTGRESQL;$(DefineConstants) USE_MYSQL;$(DefineConstants) + + 8600,8601,8602,8603,8604,8618,8625,8629 From fb6c935e7e88403aa9f6e14d1384ce88cbbfbe5d Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Sun, 27 Jul 2025 10:34:28 +0000 Subject: [PATCH 15/18] fix upcoming missions in GetUserMissionState * this is bugfix for upcoming missions issue in SoD 2.9 after 60cc00d * also removed TODO because ProductGroupID is not related to mission.GroupID and ProductGroupID filtering is covered by gameVersion --- src/Controllers/Common/ContentController.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Controllers/Common/ContentController.cs b/src/Controllers/Common/ContentController.cs index 6c72812..1c2e6eb 100644 --- a/src/Controllers/Common/ContentController.cs +++ b/src/Controllers/Common/ContentController.cs @@ -1109,14 +1109,17 @@ public class ContentController : Controller { foreach (var m in filterV2.MissionPair) if (m.MissionID != null) result.Missions.Add(missionService.GetMissionWithProgress((int)m.MissionID, viking.Id, gameVersion)); - // TODO: probably should also check for mission based on filterV2.ProductGroupID vs mission.GroupID } else { if (filterV2.GetCompletedMission ?? false) { foreach (var mission in viking.MissionStates.Where(x => x.MissionStatus == MissionStatus.Completed)) result.Missions.Add(missionService.GetMissionWithProgress(mission.MissionId, viking.Id, gameVersion)); } else { - foreach (var mission in viking.MissionStates.Where(x => x.MissionStatus != MissionStatus.Completed)) - result.Missions.Add(missionService.GetMissionWithProgress(mission.MissionId, viking.Id, gameVersion)); + var missionStatesById = viking.MissionStates.Where(x => x.MissionStatus != MissionStatus.Completed).ToDictionary(ms => ms.MissionId); + HashSet upcomingMissionIds = new(missionStore.GetUpcomingMissions(gameVersion)); + var combinedMissionIds = new HashSet(missionStatesById.Keys); + combinedMissionIds.UnionWith(upcomingMissionIds); + foreach (var missionId in combinedMissionIds) + result.Missions.Add(missionService.GetMissionWithProgress(missionId, viking.Id, gameVersion)); } } From 74b24d8ff5f544be0ebc3f00c520c9dc9699cad4 Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Thu, 17 Jul 2025 17:39:25 +0000 Subject: [PATCH 16/18] user data export and import interfce (WIP) --- .../Common/ImportExportController.cs | 146 ++++++++++++++++++ src/Model/AchievementPoints.cs | 3 + src/Model/AchievementTaskState.cs | 3 + src/Model/DBContext.cs | 3 + src/Model/Dragon.cs | 7 +- src/Model/GameData.cs | 5 +- src/Model/GameDataPair.cs | 4 + src/Model/Image.cs | 3 + src/Model/InventoryItem.cs | 4 + src/Model/MMORole.cs | 3 + src/Model/MissionState.cs | 6 +- src/Model/Neighborhood.cs | 6 +- src/Model/Pair.cs | 4 + src/Model/PairData.cs | 8 + src/Model/Party.cs | 5 +- src/Model/ProfileAnswer.cs | 4 + src/Model/Rating.cs | 4 + src/Model/RatingRank.cs | 3 + src/Model/Room.cs | 6 +- src/Model/RoomItem.cs | 4 + src/Model/SaveData.cs | 6 +- src/Model/SceneData.cs | 4 + src/Model/TaskStatus.cs | 6 +- src/Model/User.cs | 2 + src/Model/UserBadgeCompleteData.cs | 7 +- src/Model/UserMissionData.cs | 3 + src/Model/Viking.cs | 8 + 27 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 src/Controllers/Common/ImportExportController.cs diff --git a/src/Controllers/Common/ImportExportController.cs b/src/Controllers/Common/ImportExportController.cs new file mode 100644 index 0000000..b429adf --- /dev/null +++ b/src/Controllers/Common/ImportExportController.cs @@ -0,0 +1,146 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Encodings.Web; +using sodoff.Model; + +namespace sodoff.Controllers.Common; +public class ExportController : ControllerBase { + private readonly DBContext ctx; + + public ExportController(DBContext ctx) { + this.ctx = ctx; + } + + [HttpPost] + [Route("ImportExport.asmx/Export")] + public IActionResult Export([FromForm] string username, [FromForm] string password) { + // Authenticate user by Username + User? user = ctx.Users.FirstOrDefault(e => e.Username == username); + if (user is null || new PasswordHasher().VerifyHashedPassword(null, user.Password, password) == PasswordVerificationResult.Failed) { + return Unauthorized("Invalid username or password."); + } + + // Serialize to JSON + var options = new JsonSerializerOptions + { + ReferenceHandler = ReferenceHandler.IgnoreCycles, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + WriteIndented = true + }; + string jsonData = JsonSerializer.Serialize(user, options); + + return Ok(jsonData); + } + + [HttpPost] + [Route("ImportExport.asmx/Import")] + public IActionResult Import([FromForm] string username, [FromForm] string password, [FromForm] string vikingName, [FromForm] IFormFile dataFile) { + User? user = ctx.Users.FirstOrDefault(e => e.Username == username); + if (user is null || new PasswordHasher().VerifyHashedPassword(null, user.Password, password) == PasswordVerificationResult.Failed) { + return Unauthorized("Invalid username or password."); + } + + User user_data; + using (var reader = new StreamReader(dataFile.OpenReadStream())) { + user_data = System.Text.Json.JsonSerializer.Deserialize(reader.ReadToEnd()); + } + + foreach (var v in user_data.Vikings) { + if (v.Name == vikingName) { + Viking viking = new Viking { + Uid = v.Uid, // TODO check for unique or just generate new? + Name = v.Name, // TODO check for unique + User = user, + AvatarSerialized = v.AvatarSerialized, + CreationDate = v.CreationDate, // TODO or use now? + BirthDate = v.BirthDate, + Gender = v.Gender, + GameVersion = v.GameVersion + }; + user.Vikings.Add(viking); + + foreach (var x in v.Dragons) { + x.Viking = viking; + // TODO check EntityId for unique or just generate new? + x.Id = 0; // FIXME map old→new value for dragon id to update (stables) xml's + ctx.Dragons.Add(x); + } + foreach (var x in v.Images) { + x.Viking = viking; + ctx.Images.Add(x); + } + foreach (var x in v.InventoryItems) { + x.Id = 0; // FIXME map old→new value for item id to update xml's and rooms + x.Viking = viking; + ctx.InventoryItems.Add(x); + } + foreach (var x in v.Rooms) { + x.Viking = viking; + ctx.Rooms.Add(x); // FIXME need update room name (if numeric) + } + foreach (var x in v.MissionStates) { + x.Viking = viking; + ctx.MissionStates.Add(x); + } + foreach (var x in v.TaskStatuses) { + x.Viking = viking; + ctx.TaskStatuses.Add(x); + } + foreach (var x in v.AchievementTaskStates) { + x.Viking = viking; + ctx.AchievementTaskState.Add(x); + } + foreach (var x in v.AchievementPoints) { + x.Viking = viking; + ctx.AchievementPoints.Add(x); + } + foreach (var x in v.PairData) { + x.Viking = viking; + ctx.PairData.Add(x); // FIXME need update PetID in stable XML + } + foreach (var x in v.ProfileAnswers) { + x.Viking = viking; + ctx.ProfileAnswers.Add(x); + } + foreach (var x in v.GameData) { + x.Viking = viking; + ctx.GameData.Add(x); + } + foreach (var x in v.SavedData) { + x.Viking = viking; + ctx.SavedData.Add(x); + } + foreach (var x in v.Parties) { + x.Viking = viking; + ctx.Parties.Add(x); + } + foreach (var x in v.UserMissions) { + x.Viking = viking; + ctx.UserMissions.Add(x); + } + foreach (var x in v.UserBadgesCompleted) { + x.Viking = viking; + ctx.UserBadgesCompleted.Add(x); + } + if (v.Ratings.Count > 0) { + viking.Ratings = new List(); + foreach (var x in v.Ratings) { + // TODO (non-SoD) add rating via SetRating(viking, x.Rank.CategoryID, x.Rank.RatedEntityID, x.Rank.RatedUserID, x.Value); + } + } + if (v.Neighborhood != null) { + v.Neighborhood.Viking = viking; + ctx.Neighborhoods.Add(v.Neighborhood); + } + // TODO set viking.SelectedDragon + + ctx.SaveChanges(); + return Ok("OK"); + } + } + return Ok("Viking Not Found"); + } +} diff --git a/src/Model/AchievementPoints.cs b/src/Model/AchievementPoints.cs index 6cfc402..94c5b2b 100644 --- a/src/Model/AchievementPoints.cs +++ b/src/Model/AchievementPoints.cs @@ -1,12 +1,15 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class AchievementPoints { + [JsonIgnore] public int VikingId { get; set; } public int Type { get; set; } public int Value { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } } diff --git a/src/Model/AchievementTaskState.cs b/src/Model/AchievementTaskState.cs index ef2edb6..27f4f03 100644 --- a/src/Model/AchievementTaskState.cs +++ b/src/Model/AchievementTaskState.cs @@ -1,15 +1,18 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore; namespace sodoff.Model; [PrimaryKey(nameof(TaskId), nameof(VikingId))] public class AchievementTaskState { + [JsonIgnore] public int VikingId { get; set; } public int TaskId { get; set; } public int Points { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } } diff --git a/src/Model/DBContext.cs b/src/Model/DBContext.cs index 1832763..02b01a9 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 AchievementTaskState { get; set; } = null!; + public DbSet SavedData { get; set; } = null!; + public DbSet UserMissions { get; set; } = null!; public DbSet Neighborhoods { get; set; } = null!; // we had a brief debate on whether it's neighborhoods or neighborheed public DbSet Groups { get; set; } = null!; diff --git a/src/Model/Dragon.cs b/src/Model/Dragon.cs index f8f636a..b3e4ac3 100644 --- a/src/Model/Dragon.cs +++ b/src/Model/Dragon.cs @@ -1,22 +1,27 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace sodoff.Model; public class Dragon { [Key] + // [JsonIgnore] used in serialised xml (stables) [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public Guid EntityId { get; set; } + [Required] + [JsonIgnore] public int VikingId { get; set; } public string? RaisedPetData { get; set; } public int? PetXP { get; set; } - + + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; public virtual ICollection PairData { get; set; } = null!; } diff --git a/src/Model/GameData.cs b/src/Model/GameData.cs index 56f801c..7db40d3 100644 --- a/src/Model/GameData.cs +++ b/src/Model/GameData.cs @@ -1,10 +1,13 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class GameData { [Key] + [JsonIgnore] public int Id { get; set; } + [JsonIgnore] public int VikingId { get; set; } public int GameId { get; set; } @@ -15,6 +18,6 @@ public class GameData { public bool Win { get; set; } public bool Loss { get; set; } public virtual ICollection GameDataPairs { get; set; } = null!; + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; - } diff --git a/src/Model/GameDataPair.cs b/src/Model/GameDataPair.cs index 9543936..e5d45aa 100644 --- a/src/Model/GameDataPair.cs +++ b/src/Model/GameDataPair.cs @@ -1,11 +1,15 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class GameDataPair { [Key] + [JsonIgnore] public int Id { get; set; } + [JsonIgnore] public int GameDataId { get; set; } public string Name { get; set; } = null!; public int Value { get; set; } + [JsonIgnore] public virtual GameData GameData { get; set; } = null!; } diff --git a/src/Model/Image.cs b/src/Model/Image.cs index f12727c..f671c4d 100644 --- a/src/Model/Image.cs +++ b/src/Model/Image.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore; namespace sodoff.Model; @@ -12,11 +13,13 @@ public class Image { public int ImageSlot { get; set; } [Required] + [JsonIgnore] public int VikingId { get; set; } public string? ImageData { get; set; } public string? TemplateName { get; set; } + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; } diff --git a/src/Model/InventoryItem.cs b/src/Model/InventoryItem.cs index ea6c5d1..563fba9 100644 --- a/src/Model/InventoryItem.cs +++ b/src/Model/InventoryItem.cs @@ -1,18 +1,22 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model { public class InventoryItem { [Key] + // [JsonIgnore] used as room id, used in serialised xml (pairs, ...) public int Id { get; set; } public int ItemId { get; set; } + [JsonIgnore] public int VikingId { get; set; } public string? StatsSerialized { get; set; } public string? AttributesSerialized { get; set; } + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; public int Quantity { get; set; } diff --git a/src/Model/MMORole.cs b/src/Model/MMORole.cs index 8f97762..4a72c1a 100644 --- a/src/Model/MMORole.cs +++ b/src/Model/MMORole.cs @@ -1,15 +1,18 @@ using sodoff.Schema; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class MMORole { [Key] + [JsonIgnore] public int Id { get; set; } public int VikingId { get; set; } public Role Role { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } } diff --git a/src/Model/MissionState.cs b/src/Model/MissionState.cs index b82f1b0..c99d738 100644 --- a/src/Model/MissionState.cs +++ b/src/Model/MissionState.cs @@ -1,15 +1,19 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class MissionState { [Key] + [JsonIgnore] public int Id { get; set; } public int MissionId { get; set; } + [JsonIgnore] public int VikingId { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } public MissionStatus MissionStatus { get; set; } @@ -19,4 +23,4 @@ public class MissionState { public enum MissionStatus { Upcoming,Active,Completed -} \ No newline at end of file +} diff --git a/src/Model/Neighborhood.cs b/src/Model/Neighborhood.cs index a748c76..67b363c 100644 --- a/src/Model/Neighborhood.cs +++ b/src/Model/Neighborhood.cs @@ -1,18 +1,20 @@ using sodoff.Schema; using System.ComponentModel.DataAnnotations; -using System.Data; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; namespace sodoff.Model { public class Neighborhood { + [JsonIgnore] public virtual Viking? Viking { get; set; } [Key] + [JsonIgnore] public int Id { get; set; } [Required] + [JsonIgnore] public int VikingId { get; set; } [Required] diff --git a/src/Model/Pair.cs b/src/Model/Pair.cs index 5c6aca6..abc55cc 100644 --- a/src/Model/Pair.cs +++ b/src/Model/Pair.cs @@ -1,18 +1,22 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace sodoff.Model; public class Pair { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int Id { get; set; } public string Key { get; set; } = null!; public string Value { get; set; } = null!; + [JsonIgnore] public int MasterId { get; set; } + [JsonIgnore] public virtual PairData PairData { get; set; } = null!; } diff --git a/src/Model/PairData.cs b/src/Model/PairData.cs index 9f11ce5..9db929a 100644 --- a/src/Model/PairData.cs +++ b/src/Model/PairData.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace sodoff.Model; @@ -9,21 +10,28 @@ namespace sodoff.Model; public class PairData { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int Id { get; set; } public int PairId { get; set; } + [JsonIgnore] public Guid? UserId { get; set; } + [JsonIgnore] public int? VikingId { get; set; } + [JsonIgnore] public int? DragonId { get; set; } public virtual ICollection Pairs { get; set; } + [JsonIgnore] public virtual User? User { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } + [JsonIgnore] public virtual Dragon? Dragon { get; set; } } diff --git a/src/Model/Party.cs b/src/Model/Party.cs index 9667da5..dd4b5ab 100644 --- a/src/Model/Party.cs +++ b/src/Model/Party.cs @@ -1,18 +1,21 @@ using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace sodoff.Model { public class Party { [Key] + [JsonIgnore] public int Id { get; set; } public string Location { get; set; } = null!; + [JsonIgnore] public int VikingId { get; set; } public DateTime ExpirationDate { get; set; } = DateTime.UtcNow; public bool? PrivateParty { get; set; } public string LocationIconAsset { get; set; } = null!; public string AssetBundle { get; set; } = null!; + [JsonIgnore] public virtual Viking? Viking { get; set; } } } diff --git a/src/Model/ProfileAnswer.cs b/src/Model/ProfileAnswer.cs index 4aae801..ff4982b 100644 --- a/src/Model/ProfileAnswer.cs +++ b/src/Model/ProfileAnswer.cs @@ -1,15 +1,19 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model { public class ProfileAnswer { [Key] + [JsonIgnore] public int Id { get; set; } + [JsonIgnore] public int VikingId { get; set; } public int QuestionID { get; set; } public int AnswerID { get; set; } + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; } } diff --git a/src/Model/Rating.cs b/src/Model/Rating.cs index 565e736..a195a54 100644 --- a/src/Model/Rating.cs +++ b/src/Model/Rating.cs @@ -1,17 +1,21 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class Rating { [Key] + [JsonIgnore] public int Id { get; set; } + [JsonIgnore] public int VikingId { get; set; } public int RankId { get; set; } public int Value { get; set; } public DateTime Date { get; set; } + [JsonIgnore] public virtual Viking Viking { get; set; } public virtual RatingRank Rank { get; set; } } diff --git a/src/Model/RatingRank.cs b/src/Model/RatingRank.cs index 1eebec1..359f9b3 100644 --- a/src/Model/RatingRank.cs +++ b/src/Model/RatingRank.cs @@ -1,9 +1,11 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class RatingRank { [Key] + [JsonIgnore] public int Id { get; set; } public int CategoryID { get; set; } @@ -14,5 +16,6 @@ public class RatingRank { public float RatingAverage { get; set; } // On a scale of 1-5 public DateTime UpdateDate { get; set; } + [JsonIgnore] public virtual ICollection Ratings { get; set; } = null!; } diff --git a/src/Model/Room.cs b/src/Model/Room.cs index 6089e1f..6f8fe48 100644 --- a/src/Model/Room.cs +++ b/src/Model/Room.cs @@ -1,18 +1,22 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class Room { [Key] + [JsonIgnore] public int Id { get; set; } public string RoomId { get; set; } + [JsonIgnore] public int VikingId { get; set; } public string? Name { get; set; } + [JsonIgnore] 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 index 329b0bd..8701dd9 100644 --- a/src/Model/RoomItem.cs +++ b/src/Model/RoomItem.cs @@ -1,12 +1,16 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class RoomItem { [Key] + [JsonIgnore] public int Id { get; set; } + [JsonIgnore] public int RoomId { get; set; } + [JsonIgnore] public virtual Room Room { get; set; } public string RoomItemData { get; set; } diff --git a/src/Model/SaveData.cs b/src/Model/SaveData.cs index 0d411cf..f455241 100644 --- a/src/Model/SaveData.cs +++ b/src/Model/SaveData.cs @@ -1,8 +1,12 @@ -namespace sodoff.Model; +using System.Text.Json.Serialization; + +namespace sodoff.Model; public class SavedData { + [JsonIgnore] public int VikingId { get; set; } public uint SaveId { get; set; } public string? SerializedData { get; set; } + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; } diff --git a/src/Model/SceneData.cs b/src/Model/SceneData.cs index 5e17821..6a39cfc 100644 --- a/src/Model/SceneData.cs +++ b/src/Model/SceneData.cs @@ -1,14 +1,18 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model { public class SceneData { [Key] + [JsonIgnore] public int Id { get; set; } public int VikingId { get; set; } public string SceneName { get; set; } = null!; public string XmlData { get; set; } = null!; + + [JsonIgnore] public virtual Viking Viking { get; set; } = null!; } } diff --git a/src/Model/TaskStatus.cs b/src/Model/TaskStatus.cs index 9e19f2b..a83857c 100644 --- a/src/Model/TaskStatus.cs +++ b/src/Model/TaskStatus.cs @@ -1,11 +1,15 @@ -namespace sodoff.Model { +using System.Text.Json.Serialization; + +namespace sodoff.Model { public class TaskStatus { public int Id { get; set; } public int MissionId { get; set; } + [JsonIgnore] public int VikingId { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } public string? Payload { get; set; } diff --git a/src/Model/User.cs b/src/Model/User.cs index 358feb1..2d3d579 100644 --- a/src/Model/User.cs +++ b/src/Model/User.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace sodoff.Model; public class User { @@ -14,6 +15,7 @@ public class User { [Required] public string Password { get; set; } = null!; + [JsonIgnore] public virtual ICollection Sessions { get; set; } = null!; public virtual ICollection Vikings { get; set; } = null!; public virtual ICollection PairData { get; set; } = null!; diff --git a/src/Model/UserBadgeCompleteData.cs b/src/Model/UserBadgeCompleteData.cs index efab4c9..d96eafd 100644 --- a/src/Model/UserBadgeCompleteData.cs +++ b/src/Model/UserBadgeCompleteData.cs @@ -1,11 +1,16 @@ -namespace sodoff.Model +using System.Text.Json.Serialization; + +namespace sodoff.Model { public class UserBadgeCompleteData { + [JsonIgnore] public int Id { get; set; } + [JsonIgnore] public int VikingId { get; set; } public int BadgeId { get; set; } + [JsonIgnore] public virtual Viking? Viking { get; set; } } } diff --git a/src/Model/UserMissionData.cs b/src/Model/UserMissionData.cs index 1a971b9..16a5cf8 100644 --- a/src/Model/UserMissionData.cs +++ b/src/Model/UserMissionData.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore; namespace sodoff.Model @@ -6,6 +7,7 @@ namespace sodoff.Model [PrimaryKey(nameof(VikingId), nameof(WorldId), nameof(MissionId))] public class UserMissionData { + [JsonIgnore] public int VikingId { get; set; } public int WorldId { get; set; } public int MissionId { get; set; } @@ -13,6 +15,7 @@ namespace sodoff.Model public int TaskId { get; set; } public bool IsCompleted { get; set; } = false; + [JsonIgnore] public virtual Viking? Viking { get; set; } } } diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index a787107..e2b8ca4 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using sodoff.Schema; namespace sodoff.Model; @@ -7,6 +8,7 @@ namespace sodoff.Model; [Index(nameof(Uid))] public class Viking { [Key] + [JsonIgnore] public int Id { get; set; } public Guid Uid { get; set; } @@ -15,13 +17,17 @@ public class Viking { public string Name { get; set; } = null!; [Required] + [JsonIgnore] public Guid UserId { get; set; } public string? AvatarSerialized { get; set; } + [JsonIgnore] public int? SelectedDragonId { get; set; } + [JsonIgnore] public virtual ICollection Sessions { get; set; } = null!; + [JsonIgnore] public virtual User User { get; set; } = null!; public virtual ICollection Dragons { get; set; } = null!; public virtual ICollection Images { get; set; } = null!; @@ -37,8 +43,10 @@ public class Viking { public virtual ICollection ProfileAnswers { get; set; } = null!; public virtual ICollection SavedData { get; set; } = null!; public virtual ICollection Parties { get; set; } = null!; + [JsonIgnore] public virtual ICollection MMORoles { get; set; } = null!; public virtual Neighborhood? Neighborhood { get; set; } = null!; + [JsonIgnore] public virtual ICollection Groups { get; set; } = null!; public virtual ICollection Ratings { get; set; } = null!; public virtual Dragon? SelectedDragon { get; set; } From ea75d182a6a76d07927500626364a71285229903 Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Mon, 28 Jul 2025 09:43:36 +0000 Subject: [PATCH 17/18] user data export and import interfce (enhance) * update items and dragons id on import * check for viking name unique * add unique constraints in database * add simple import/export html form for localhosted srvers --- .../Common/ImportExportController.cs | 95 +++++++++++++++---- src/Model/Dragon.cs | 4 +- src/Model/User.cs | 5 +- src/Model/Viking.cs | 2 +- src/Resources/html/export.xml | 16 ++++ src/Resources/html/import.xml | 24 +++++ src/Schema/NestData.cs | 13 +++ src/Schema/StableData.cs | 22 +++++ src/Schema/UserRankData.cs | 23 +++++ src/sodoff.csproj | 6 ++ 10 files changed, 188 insertions(+), 22 deletions(-) create mode 100644 src/Resources/html/export.xml create mode 100644 src/Resources/html/import.xml create mode 100644 src/Schema/NestData.cs create mode 100644 src/Schema/StableData.cs create mode 100644 src/Schema/UserRankData.cs diff --git a/src/Controllers/Common/ImportExportController.cs b/src/Controllers/Common/ImportExportController.cs index b429adf..1631bbf 100644 --- a/src/Controllers/Common/ImportExportController.cs +++ b/src/Controllers/Common/ImportExportController.cs @@ -5,6 +5,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Encodings.Web; using sodoff.Model; +using sodoff.Schema; +using sodoff.Util; namespace sodoff.Controllers.Common; public class ExportController : ControllerBase { @@ -15,7 +17,7 @@ public class ExportController : ControllerBase { } [HttpPost] - [Route("ImportExport.asmx/Export")] + [Route("Export")] public IActionResult Export([FromForm] string username, [FromForm] string password) { // Authenticate user by Username User? user = ctx.Users.FirstOrDefault(e => e.Username == username); @@ -36,8 +38,8 @@ public class ExportController : ControllerBase { } [HttpPost] - [Route("ImportExport.asmx/Import")] - public IActionResult Import([FromForm] string username, [FromForm] string password, [FromForm] string vikingName, [FromForm] IFormFile dataFile) { + [Route("Import")] + public IActionResult Import([FromForm] string username, [FromForm] string password, [FromForm] string vikingName, [FromForm] IFormFile dataFile, [FromForm] string? newVikingName) { User? user = ctx.Users.FirstOrDefault(e => e.Username == username); if (user is null || new PasswordHasher().VerifyHashedPassword(null, user.Password, password) == PasswordVerificationResult.Failed) { return Unauthorized("Invalid username or password."); @@ -50,36 +52,81 @@ public class ExportController : ControllerBase { foreach (var v in user_data.Vikings) { if (v.Name == vikingName) { + if (String.IsNullOrEmpty(newVikingName)) + newVikingName = vikingName; + + if (ctx.Vikings.Count(e => e.Name == newVikingName) > 0) { + return Conflict("Viking name already in use"); + } + + if (newVikingName != vikingName) { + AvatarData avatarData = XmlUtil.DeserializeXml(v.AvatarSerialized); + avatarData.DisplayName = newVikingName; + v.AvatarSerialized = XmlUtil.SerializeXml(avatarData); + } + Viking viking = new Viking { - Uid = v.Uid, // TODO check for unique or just generate new? - Name = v.Name, // TODO check for unique + Uid = Guid.NewGuid(), + Name = newVikingName, User = user, AvatarSerialized = v.AvatarSerialized, - CreationDate = v.CreationDate, // TODO or use now? + CreationDate = DateTime.UtcNow, BirthDate = v.BirthDate, Gender = v.Gender, GameVersion = v.GameVersion }; user.Vikings.Add(viking); + Dictionary dragonIds = new(); foreach (var x in v.Dragons) { x.Viking = viking; - // TODO check EntityId for unique or just generate new? - x.Id = 0; // FIXME map old→new value for dragon id to update (stables) xml's + x.EntityId = Guid.NewGuid(); + dragonIds.Add(x.Id, x.EntityId); + x.Id = 0; ctx.Dragons.Add(x); } - foreach (var x in v.Images) { - x.Viking = viking; - ctx.Images.Add(x); - } + Dictionary itemIds = new(); foreach (var x in v.InventoryItems) { - x.Id = 0; // FIXME map old→new value for item id to update xml's and rooms + itemIds.Add(x.Id, x.ItemId); + x.Id = 0; x.Viking = viking; ctx.InventoryItems.Add(x); } + + ctx.SaveChanges(); // need for get new ids of dragons and items + + HashSet usedItemIds = new(); foreach (var x in v.Rooms) { x.Viking = viking; - ctx.Rooms.Add(x); // FIXME need update room name (if numeric) + if (int.TryParse(x.RoomId, out int roomID)) { + // numeric room name is inventory item id + // remap old value to new value based on item id value + roomID = viking.InventoryItems.FirstOrDefault(e => e.ItemId == itemIds[roomID] && !usedItemIds.Contains(e.Id)).Id; + usedItemIds.Add(roomID); + x.RoomId = roomID.ToString(); + } + ctx.Rooms.Add(x); + } + foreach (var x in v.PairData) { + x.Viking = viking; + if (x.PairId == 2014) { // stables data + foreach (var p in x.Pairs.Where(e => e.Key.StartsWith("Stable"))) { + StableData stableData = XmlUtil.DeserializeXml(p.Value); + stableData.InventoryID = viking.InventoryItems.FirstOrDefault(e => e.ItemId == stableData.ItemID && !usedItemIds.Contains(e.Id)).Id; + usedItemIds.Add(stableData.InventoryID); + foreach (var n in stableData.NestList) { + if (n.PetID != 0) + n.PetID = viking.Dragons.FirstOrDefault(d => d.EntityId == dragonIds[n.PetID]).Id; + } + p.Value = XmlUtil.SerializeXml(stableData); + } + } + ctx.PairData.Add(x); + } + + foreach (var x in v.Images) { + x.Viking = viking; + ctx.Images.Add(x); } foreach (var x in v.MissionStates) { x.Viking = viking; @@ -97,10 +144,6 @@ public class ExportController : ControllerBase { x.Viking = viking; ctx.AchievementPoints.Add(x); } - foreach (var x in v.PairData) { - x.Viking = viking; - ctx.PairData.Add(x); // FIXME need update PetID in stable XML - } foreach (var x in v.ProfileAnswers) { x.Viking = viking; ctx.ProfileAnswers.Add(x); @@ -135,7 +178,9 @@ public class ExportController : ControllerBase { v.Neighborhood.Viking = viking; ctx.Neighborhoods.Add(v.Neighborhood); } - // TODO set viking.SelectedDragon + + if (v.SelectedDragon != null) + viking.SelectedDragon = viking.Dragons.FirstOrDefault(d => d.EntityId == dragonIds[v.SelectedDragon.Id]); ctx.SaveChanges(); return Ok("OK"); @@ -143,4 +188,16 @@ public class ExportController : ControllerBase { } return Ok("Viking Not Found"); } + + [HttpGet] + [Route("Export")] + public IActionResult Export() { + return Content(XmlUtil.ReadResourceXmlString("html.export"), "application/xhtml+xml"); + } + + [HttpGet] + [Route("Import")] + public IActionResult Import() { + return Content(XmlUtil.ReadResourceXmlString("html.import"), "application/xhtml+xml"); + } } diff --git a/src/Model/Dragon.cs b/src/Model/Dragon.cs index b3e4ac3..cdfd831 100644 --- a/src/Model/Dragon.cs +++ b/src/Model/Dragon.cs @@ -1,9 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; namespace sodoff.Model; +[Index(nameof(EntityId), IsUnique = true)] public class Dragon { [Key] // [JsonIgnore] used in serialised xml (stables) diff --git a/src/Model/User.cs b/src/Model/User.cs index 2d3d579..de4beb3 100644 --- a/src/Model/User.cs +++ b/src/Model/User.cs @@ -1,7 +1,10 @@ -using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; namespace sodoff.Model; + +[Index(nameof(Username), IsUnique = true)] public class User { [Key] public Guid Id { get; set; } diff --git a/src/Model/Viking.cs b/src/Model/Viking.cs index e2b8ca4..86a86e9 100644 --- a/src/Model/Viking.cs +++ b/src/Model/Viking.cs @@ -5,7 +5,7 @@ using sodoff.Schema; namespace sodoff.Model; -[Index(nameof(Uid))] +[Index(nameof(Uid), IsUnique = true)] public class Viking { [Key] [JsonIgnore] diff --git a/src/Resources/html/export.xml b/src/Resources/html/export.xml new file mode 100644 index 0000000..d93c359 --- /dev/null +++ b/src/Resources/html/export.xml @@ -0,0 +1,16 @@ + + + + + Export SoDOff account + + +
+
+
+
+

+ +
+ + diff --git a/src/Resources/html/import.xml b/src/Resources/html/import.xml new file mode 100644 index 0000000..3ed291c --- /dev/null +++ b/src/Resources/html/import.xml @@ -0,0 +1,24 @@ + + + + + Import SoDOff account + + +
+
+
+
+

+ +
+
+
+
+
+

+ + +
+ + diff --git a/src/Schema/NestData.cs b/src/Schema/NestData.cs new file mode 100644 index 0000000..c115c54 --- /dev/null +++ b/src/Schema/NestData.cs @@ -0,0 +1,13 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "NestData", Namespace = "")] +[Serializable] +public class NestData { + [XmlElement(ElementName = "PetID")] + public int PetID; + + [XmlElement(ElementName = "ID")] + public int ID; +} diff --git a/src/Schema/StableData.cs b/src/Schema/StableData.cs new file mode 100644 index 0000000..dff5268 --- /dev/null +++ b/src/Schema/StableData.cs @@ -0,0 +1,22 @@ +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "StableData", Namespace = "")] +[Serializable] +public class StableData { + [XmlElement(ElementName = "Name")] + public string Name; + + [XmlElement(ElementName = "ID")] + public int ID; + + [XmlElement(ElementName = "ItemID")] + public int ItemID; + + [XmlElement(ElementName = "InventoryID")] + public int InventoryID; + + [XmlElement(ElementName = "Nests")] + public List NestList; +} diff --git a/src/Schema/UserRankData.cs b/src/Schema/UserRankData.cs new file mode 100644 index 0000000..fa9fc48 --- /dev/null +++ b/src/Schema/UserRankData.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; +using System.Xml.Serialization; + +namespace sodoff.Schema; + +[XmlRoot(ElementName = "UserRankData", Namespace = "")] +[Serializable] +public class UserRankData { + [XmlElement(ElementName = "UserID")] + public Guid UserID; + + [XmlElement(ElementName = "Points")] + public int Points; + + [XmlElement(ElementName = "CurrentRank")] + public UserRank CurrentRank; + + [XmlElement(ElementName = "MemberRank")] + public UserRank MemberRank; + + [XmlElement(ElementName = "NextRank")] + public UserRank NextRank; +} diff --git a/src/sodoff.csproj b/src/sodoff.csproj index cab8f4d..4e30ed9 100644 --- a/src/sodoff.csproj +++ b/src/sodoff.csproj @@ -155,5 +155,11 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + From 59c722fe65bc0fc9fb5fb8b0ec7d0226c1fe10f7 Mon Sep 17 00:00:00 2001 From: Robert Paciorek Date: Tue, 12 Aug 2025 20:36:44 +0000 Subject: [PATCH 18/18] importer bugfix - error on stable imports stables do not use unique inventory slots --- src/Controllers/Common/ImportExportController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controllers/Common/ImportExportController.cs b/src/Controllers/Common/ImportExportController.cs index 1631bbf..92dfea9 100644 --- a/src/Controllers/Common/ImportExportController.cs +++ b/src/Controllers/Common/ImportExportController.cs @@ -112,7 +112,7 @@ public class ExportController : ControllerBase { if (x.PairId == 2014) { // stables data foreach (var p in x.Pairs.Where(e => e.Key.StartsWith("Stable"))) { StableData stableData = XmlUtil.DeserializeXml(p.Value); - stableData.InventoryID = viking.InventoryItems.FirstOrDefault(e => e.ItemId == stableData.ItemID && !usedItemIds.Contains(e.Id)).Id; + stableData.InventoryID = viking.InventoryItems.FirstOrDefault(e => e.ItemId == stableData.ItemID).Id; usedItemIds.Add(stableData.InventoryID); foreach (var n in stableData.NestList) { if (n.PetID != 0)