diff --git a/Maple2.File.Parser/Maple2.File.Parser.csproj b/Maple2.File.Parser/Maple2.File.Parser.csproj index 86883bf..dc10057 100644 --- a/Maple2.File.Parser/Maple2.File.Parser.csproj +++ b/Maple2.File.Parser/Maple2.File.Parser.csproj @@ -13,7 +13,7 @@ MapleStory2, File, Parser, m2d, xml true - 2.4.15 + 2.4.16 net8.0 README.md enable diff --git a/Maple2.File.Parser/ServerTableParser.cs b/Maple2.File.Parser/ServerTableParser.cs index 12569fd..1369b9d 100644 --- a/Maple2.File.Parser/ServerTableParser.cs +++ b/Maple2.File.Parser/ServerTableParser.cs @@ -15,6 +15,8 @@ using ItemMergeOptionRoot = Maple2.File.Parser.Xml.Table.Server.ItemMergeOptionRoot; using ItemOptionVariation = Maple2.File.Parser.Xml.Table.Server.ItemOptionVariation; using MergeOption = Maple2.File.Parser.Xml.Table.Server.MergeOption; +using MaidRecipe = Maple2.File.Parser.Xml.Table.Server.MaidRecipe; +using MaidRecipeRoot = Maple2.File.Parser.Xml.Table.Server.MaidRecipeRoot; namespace Maple2.File.Parser; @@ -61,6 +63,8 @@ public class ServerTableParser { private readonly XmlSerializer constantsSerializer; private readonly XmlSerializer npcStatFactorByPlayerCountSerializer; private readonly XmlSerializer npcStatFactorByLevelSerializer; + private readonly XmlSerializer maidGradeInfoSerializer; + private readonly XmlSerializer maidRecipeSerializer; public ServerTableParser(M2dReader xmlReader) { this.xmlReader = xmlReader; @@ -105,6 +109,8 @@ public ServerTableParser(M2dReader xmlReader) { constantsSerializer = new XmlSerializer(typeof(Constants)); npcStatFactorByPlayerCountSerializer = new XmlSerializer(typeof(NpcStatFactorByPlayerCountRoot)); npcStatFactorByLevelSerializer = new XmlSerializer(typeof(NpcStatFactorByLevelRoot)); + maidGradeInfoSerializer = new XmlSerializer(typeof(MaidGradeInfoRoot)); + maidRecipeSerializer = new XmlSerializer(typeof(MaidRecipeRoot)); // var seen = new HashSet(); // this.bankTypeSerializer.UnknownAttribute += (sender, args) => { @@ -728,4 +734,26 @@ public IEnumerable ParseNpcStatFactorByLevel() { yield return entry; } } + + public IEnumerable<(int Grade, MaidGradeInfo GradeInfo)> ParseMaidGradeInfo() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry("table/Server/MaidGradeInfo.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidGradeInfoSerializer.Deserialize(reader) as MaidGradeInfoRoot; + Debug.Assert(data != null); + + foreach (MaidGradeInfo entry in data.Grade) { + yield return (entry.Grade, entry); + } + } + + public IEnumerable<(int Id, MaidRecipe Recipe)> ParseMaidRecipe() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry("table/Server/MaidRecipeSvr.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidRecipeSerializer.Deserialize(reader) as MaidRecipeRoot; + Debug.Assert(data != null); + + foreach (MaidRecipe entry in data.recipe) { + yield return (entry.Id, entry); + } + } } diff --git a/Maple2.File.Parser/TableParser.cs b/Maple2.File.Parser/TableParser.cs index 255b4d1..29ea37e 100644 --- a/Maple2.File.Parser/TableParser.cs +++ b/Maple2.File.Parser/TableParser.cs @@ -117,6 +117,11 @@ public class TableParser { private readonly XmlSerializer fameLogSerializer; private readonly XmlSerializer famePickMethodSerializer; private readonly XmlSerializer characterAbilitySerializer; + private readonly XmlSerializer maidExpSerializer; + private readonly XmlSerializer maidPropertySerializer; + private readonly XmlSerializer maidRecipeSerializer; + private readonly XmlSerializer maidRecipeGroupSerializer; + private readonly XmlSerializer maidSalarySerializer; private readonly string locale; private readonly string language; @@ -228,6 +233,11 @@ public TableParser(M2dReader xmlReader, string language) { fameLogSerializer = new XmlSerializer(typeof(FameLogRoot)); famePickMethodSerializer = new XmlSerializer(typeof(FamePickMethod)); characterAbilitySerializer = new XmlSerializer(typeof(CharacterAbilityRoot)); + maidExpSerializer = new XmlSerializer(typeof(MaidExpRoot)); + maidPropertySerializer = new XmlSerializer(typeof(MaidPropertyRoot)); + maidRecipeSerializer = new XmlSerializer(typeof(MaidRecipeRoot)); + maidRecipeGroupSerializer = new XmlSerializer(typeof(MaidRecipeGroupRoot)); + maidSalarySerializer = new XmlSerializer(typeof(MaidSalaryRoot)); locale = FeatureLocaleFilter.Locale.ToLower(); this.language = language; @@ -1746,4 +1756,59 @@ public IEnumerable ParseJobTableNew() { yield return (entry.id, entry); } } + + public IEnumerable<(int Level, MaidExp Exp)> ParseMaidExp() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry($"table/maidexp.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidExpSerializer.Deserialize(reader) as MaidExpRoot; + Debug.Assert(data != null); + + foreach (MaidExp entry in data.Exp) { + yield return (entry.Level, entry); + } + } + + public IEnumerable<(int MaidId, MaidProperty Property)> ParseMaidProperty() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry($"table/maidproperty.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidPropertySerializer.Deserialize(reader) as MaidPropertyRoot; + Debug.Assert(data != null); + + foreach (MaidProperty entry in data.Property) { + yield return (entry.MaidID, entry); + } + } + + public IEnumerable<(int Id, MaidRecipe Recipe)> ParseMaidRecipe() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry($"table/maidrecipe.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidRecipeSerializer.Deserialize(reader) as MaidRecipeRoot; + Debug.Assert(data != null); + + foreach (MaidRecipe entry in data.recipe) { + yield return (entry.Id, entry); + } + } + + public IEnumerable<(int GroupId, MaidRecipeGroup Group)> ParseMaidRecipeGroup() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry($"table/maidrecipegroup.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidRecipeGroupSerializer.Deserialize(reader) as MaidRecipeGroupRoot; + Debug.Assert(data != null); + + foreach (MaidRecipeGroup entry in data.group) { + yield return (entry.GroupID, entry); + } + } + + public IEnumerable<(int Id, MaidSalary Salary)> ParseMaidSalary() { + string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry($"table/{locale}/maidsalary.xml"))); + var reader = XmlReader.Create(new StringReader(xml)); + var data = maidSalarySerializer.Deserialize(reader) as MaidSalaryRoot; + Debug.Assert(data != null); + + foreach (MaidSalary entry in data.key) { + yield return (entry.id, entry); + } + } } diff --git a/Maple2.File.Parser/Xml/Table/MaidExp.cs b/Maple2.File.Parser/Xml/Table/MaidExp.cs new file mode 100644 index 0000000..34890f0 --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/MaidExp.cs @@ -0,0 +1,14 @@ +using System.Xml.Serialization; + +namespace Maple2.File.Parser.Xml.Table; + +// ./data/xml/table/maidexp.xml +[XmlRoot("ms2")] +public class MaidExpRoot { + [XmlElement] public List Exp; +} + +public class MaidExp { + [XmlAttribute] public int Level; + [XmlAttribute] public int Exp; +} diff --git a/Maple2.File.Parser/Xml/Table/MaidProperty.cs b/Maple2.File.Parser/Xml/Table/MaidProperty.cs new file mode 100644 index 0000000..102bb6a --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/MaidProperty.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace Maple2.File.Parser.Xml.Table; + +// ./data/xml/table/maidproperty.xml +[XmlRoot("ms2")] +public class MaidPropertyRoot { + [XmlElement] public List Property; +} + +public class MaidProperty { + [XmlAttribute] public int MaidID; + [XmlAttribute] public int RecipeGroupID; + [XmlAttribute] public int NPCID; +} diff --git a/Maple2.File.Parser/Xml/Table/MaidRecipe.cs b/Maple2.File.Parser/Xml/Table/MaidRecipe.cs new file mode 100644 index 0000000..68309f1 --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/MaidRecipe.cs @@ -0,0 +1,30 @@ +using System.Xml.Serialization; +using M2dXmlGenerator; + +namespace Maple2.File.Parser.Xml.Table; + +// ./data/xml/table/maidrecipe.xml +[XmlRoot("ms2")] +public partial class MaidRecipeRoot { + [M2dFeatureLocale(Selector = "Id")] private IList _recipe; +} + +public partial class MaidRecipe : IFeatureLocale { + [XmlAttribute] public int Id; + [XmlAttribute] public string FirstIngredientItemID = string.Empty; + [XmlAttribute] public int FirstIngredientCount; + [XmlAttribute] public string SecondIngredientItemID = string.Empty; + [XmlAttribute] public int SecondIngredientCount; + [XmlAttribute] public string ThirdIngredientItemID = string.Empty; + [XmlAttribute] public int ThirdIngredientCount; + [XmlAttribute] public int WorkbenchType; + [XmlAttribute] public int LeadTimeNormal; + [XmlAttribute] public int LeadTimeGood; + [XmlAttribute] public int LeadTimeVeryGood; + [XmlAttribute] public int MaidExp; + [XmlAttribute] public int MaidMood; + [XmlAttribute] public int ProductItemID; + [XmlAttribute] public int ProductsocketDataID; + [XmlAttribute] public int ProductCount; + [XmlAttribute] public int ProductRank; +} diff --git a/Maple2.File.Parser/Xml/Table/MaidRecipeGroup.cs b/Maple2.File.Parser/Xml/Table/MaidRecipeGroup.cs new file mode 100644 index 0000000..4f8fb50 --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/MaidRecipeGroup.cs @@ -0,0 +1,16 @@ +using System.Xml.Serialization; +using M2dXmlGenerator; + +namespace Maple2.File.Parser.Xml.Table; + +// ./data/xml/table/maidrecipegroup.xml +[XmlRoot("ms2")] +public class MaidRecipeGroupRoot { + [XmlElement] public List group; +} + +public partial class MaidRecipeGroup { + [XmlAttribute] public int GroupID; + [M2dArray] public int[] RecipeIDs; + [M2dArray] public int[] RequireLevels; +} diff --git a/Maple2.File.Parser/Xml/Table/MaidSalary.cs b/Maple2.File.Parser/Xml/Table/MaidSalary.cs new file mode 100644 index 0000000..811589b --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/MaidSalary.cs @@ -0,0 +1,15 @@ +using System.Xml.Serialization; + +namespace Maple2.File.Parser.Xml.Table; + +// ./data/xml/table/na/maidsalary.xml +[XmlRoot("ms2")] +public class MaidSalaryRoot { + [XmlElement] public List key; +} + +public partial class MaidSalary { + [XmlAttribute] public int id; + [XmlAttribute] public int SalaryType; + [XmlAttribute] public int SalaryAmount; +} diff --git a/Maple2.File.Parser/Xml/Table/Server/MaidGradeInfo.cs b/Maple2.File.Parser/Xml/Table/Server/MaidGradeInfo.cs new file mode 100644 index 0000000..230658b --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/Server/MaidGradeInfo.cs @@ -0,0 +1,17 @@ +using System.Xml.Serialization; + +namespace Maple2.File.Parser.Xml.Table.Server; + +// ./data/server/table/Server/MaidGradeInfo.xml +[XmlRoot("ms2")] +public class MaidGradeInfoRoot { + [XmlElement] public List Grade; +} + +public class MaidGradeInfo { + [XmlAttribute] public int Grade; + [XmlAttribute] public float JackpotRate; + [XmlAttribute] public float FeelNormalRate; + [XmlAttribute] public float FeelGoodRate; + [XmlAttribute] public float FeelVeryGoodRate; +} diff --git a/Maple2.File.Parser/Xml/Table/Server/MaidRecipeSvr.cs b/Maple2.File.Parser/Xml/Table/Server/MaidRecipeSvr.cs new file mode 100644 index 0000000..7904103 --- /dev/null +++ b/Maple2.File.Parser/Xml/Table/Server/MaidRecipeSvr.cs @@ -0,0 +1,36 @@ +using System.Xml.Serialization; +using M2dXmlGenerator; + +namespace Maple2.File.Parser.Xml.Table.Server; + +// ./data/server/table/Server/MaidRecipeSvr.xml +[XmlRoot("ms2")] +public partial class MaidRecipeRoot { + [M2dFeatureLocale(Selector = "Id")] private IList _recipe; +} + +public partial class MaidRecipe : IFeatureLocale { + [XmlAttribute] public int Id; + [XmlAttribute] public string FirstIngredientItemID = string.Empty; + [XmlAttribute] public int FirstIngredientCount; + [XmlAttribute] public string SecondIngredientItemID = string.Empty; + [XmlAttribute] public int SecondIngredientCount; + [XmlAttribute] public string ThirdIngredientItemID = string.Empty; + [XmlAttribute] public int ThirdIngredientCount; + [XmlAttribute] public int WorkbenchType; + [XmlAttribute] public int LeadTimeNormal; + [XmlAttribute] public int LeadTimeGood; + [XmlAttribute] public int LeadTimeVeryGood; + [XmlAttribute] public int MaidExp; + [XmlAttribute] public int ProductItemID; + [XmlAttribute] public int ProductsocketDataID; + [XmlAttribute] public int ProductCount; + [XmlAttribute] public int ProductRank; + [XmlAttribute] public int JackpotItemID; + [XmlAttribute] public int JackpotsocketDataID; + [XmlAttribute] public int JackpotCount; + [XmlAttribute] public int JackpotRank; + [XmlAttribute] public float JackpotRate; + [XmlAttribute] public int JackpotMood; + [XmlAttribute] public int ImmediatelyCompleteFee; +} diff --git a/Maple2.File.Tests/ServerTableParserTest.cs b/Maple2.File.Tests/ServerTableParserTest.cs index 3692d91..efcbb27 100644 --- a/Maple2.File.Tests/ServerTableParserTest.cs +++ b/Maple2.File.Tests/ServerTableParserTest.cs @@ -464,5 +464,23 @@ public void TestNpcStatFactorByLevel() { continue; } } + + [TestMethod] + public void TestMaidGradeInfo() { + var parser = new ServerTableParser(TestUtils.ServerReader); + + foreach ((_, _) in parser.ParseMaidGradeInfo()) { + continue; + } + } + + [TestMethod] + public void TestMaidRecipe() { + var parser = new ServerTableParser(TestUtils.ServerReader); + + foreach ((_, _) in parser.ParseMaidRecipe()) { + continue; + } + } } diff --git a/Maple2.File.Tests/TableParserTest.cs b/Maple2.File.Tests/TableParserTest.cs index 38ab84a..2576faa 100644 --- a/Maple2.File.Tests/TableParserTest.cs +++ b/Maple2.File.Tests/TableParserTest.cs @@ -843,4 +843,23 @@ public void TestCharacterAbility() { continue; } } + + [TestMethod] + public void TestMaid() { + foreach ((_, _) in _parser.ParseMaidExp()) { + continue; + } + foreach ((_, _) in _parser.ParseMaidProperty()) { + continue; + } + foreach ((_, _) in _parser.ParseMaidRecipe()) { + continue; + } + foreach ((_, _) in _parser.ParseMaidRecipeGroup()) { + continue; + } + foreach ((_, _) in _parser.ParseMaidSalary()) { + continue; + } + } }